123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389 |
- /* Copyright (C) 2009-2022 Free Software Foundation, Inc.
- This file is part of GDB.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
- #include "defs.h"
- #include "osabi.h"
- #include "amd64-tdep.h"
- #include "gdbsupport/x86-xstate.h"
- #include "gdbtypes.h"
- #include "gdbcore.h"
- #include "regcache.h"
- #include "windows-tdep.h"
- #include "frame.h"
- #include "objfiles.h"
- #include "frame-unwind.h"
- #include "coff/internal.h"
- #include "coff/i386.h"
- #include "coff/pe.h"
- #include "libcoff.h"
- #include "value.h"
- #include <algorithm>
- /* The registers used to pass integer arguments during a function call. */
- static int amd64_windows_dummy_call_integer_regs[] =
- {
- AMD64_RCX_REGNUM, /* %rcx */
- AMD64_RDX_REGNUM, /* %rdx */
- AMD64_R8_REGNUM, /* %r8 */
- AMD64_R9_REGNUM /* %r9 */
- };
- /* This vector maps GDB's idea of a register's number into an offset into
- the Windows API CONTEXT structure. */
- static int amd64_windows_gregset_reg_offset[] =
- {
- 120, /* Rax */
- 144, /* Rbx */
- 128, /* Rcx */
- 136, /* Rdx */
- 168, /* Rsi */
- 176, /* Rdi */
- 160, /* Rbp */
- 152, /* Rsp */
- 184, /* R8 */
- 192, /* R9 */
- 200, /* R10 */
- 208, /* R11 */
- 216, /* R12 */
- 224, /* R13 */
- 232, /* R14 */
- 240, /* R15 */
- 248, /* Rip */
- 68, /* EFlags */
- 56, /* SegCs */
- 66, /* SegSs */
- 58, /* SegDs */
- 60, /* SegEs */
- 62, /* SegFs */
- 64, /* SegGs */
- 288, /* FloatSave.FloatRegisters[0] */
- 304, /* FloatSave.FloatRegisters[1] */
- 320, /* FloatSave.FloatRegisters[2] */
- 336, /* FloatSave.FloatRegisters[3] */
- 352, /* FloatSave.FloatRegisters[4] */
- 368, /* FloatSave.FloatRegisters[5] */
- 384, /* FloatSave.FloatRegisters[6] */
- 400, /* FloatSave.FloatRegisters[7] */
- 256, /* FloatSave.ControlWord */
- 258, /* FloatSave.StatusWord */
- 260, /* FloatSave.TagWord */
- 268, /* FloatSave.ErrorSelector */
- 264, /* FloatSave.ErrorOffset */
- 276, /* FloatSave.DataSelector */
- 272, /* FloatSave.DataOffset */
- 268, /* FloatSave.ErrorSelector */
- 416, /* Xmm0 */
- 432, /* Xmm1 */
- 448, /* Xmm2 */
- 464, /* Xmm3 */
- 480, /* Xmm4 */
- 496, /* Xmm5 */
- 512, /* Xmm6 */
- 528, /* Xmm7 */
- 544, /* Xmm8 */
- 560, /* Xmm9 */
- 576, /* Xmm10 */
- 592, /* Xmm11 */
- 608, /* Xmm12 */
- 624, /* Xmm13 */
- 640, /* Xmm14 */
- 656, /* Xmm15 */
- 280, /* FloatSave.MxCsr */
- };
- #define AMD64_WINDOWS_SIZEOF_GREGSET 1232
- /* Return nonzero if an argument of type TYPE should be passed
- via one of the integer registers. */
- static int
- amd64_windows_passed_by_integer_register (struct type *type)
- {
- switch (type->code ())
- {
- case TYPE_CODE_INT:
- case TYPE_CODE_ENUM:
- case TYPE_CODE_BOOL:
- case TYPE_CODE_RANGE:
- case TYPE_CODE_CHAR:
- case TYPE_CODE_PTR:
- case TYPE_CODE_REF:
- case TYPE_CODE_RVALUE_REF:
- case TYPE_CODE_STRUCT:
- case TYPE_CODE_UNION:
- case TYPE_CODE_COMPLEX:
- return (TYPE_LENGTH (type) == 1
- || TYPE_LENGTH (type) == 2
- || TYPE_LENGTH (type) == 4
- || TYPE_LENGTH (type) == 8);
- default:
- return 0;
- }
- }
- /* Return nonzero if an argument of type TYPE should be passed
- via one of the XMM registers. */
- static int
- amd64_windows_passed_by_xmm_register (struct type *type)
- {
- return ((type->code () == TYPE_CODE_FLT
- || type->code () == TYPE_CODE_DECFLOAT)
- && (TYPE_LENGTH (type) == 4 || TYPE_LENGTH (type) == 8));
- }
- /* Return non-zero iff an argument of the given TYPE should be passed
- by pointer. */
- static int
- amd64_windows_passed_by_pointer (struct type *type)
- {
- if (amd64_windows_passed_by_integer_register (type))
- return 0;
- if (amd64_windows_passed_by_xmm_register (type))
- return 0;
- return 1;
- }
- /* For each argument that should be passed by pointer, reserve some
- stack space, store a copy of the argument on the stack, and replace
- the argument by its address. Return the new Stack Pointer value.
- NARGS is the number of arguments. ARGS is the array containing
- the value of each argument. SP is value of the Stack Pointer. */
- static CORE_ADDR
- amd64_windows_adjust_args_passed_by_pointer (struct value **args,
- int nargs, CORE_ADDR sp)
- {
- int i;
- for (i = 0; i < nargs; i++)
- if (amd64_windows_passed_by_pointer (value_type (args[i])))
- {
- struct type *type = value_type (args[i]);
- const gdb_byte *valbuf = value_contents (args[i]).data ();
- const int len = TYPE_LENGTH (type);
- /* Store a copy of that argument on the stack, aligned to
- a 16 bytes boundary, and then use the copy's address as
- the argument. */
- sp -= len;
- sp &= ~0xf;
- write_memory (sp, valbuf, len);
- args[i]
- = value_addr (value_from_contents_and_address (type, valbuf, sp));
- }
- return sp;
- }
- /* Store the value of ARG in register REGNO (right-justified).
- REGCACHE is the register cache. */
- static void
- amd64_windows_store_arg_in_reg (struct regcache *regcache,
- struct value *arg, int regno)
- {
- struct type *type = value_type (arg);
- const gdb_byte *valbuf = value_contents (arg).data ();
- gdb_byte buf[8];
- gdb_assert (TYPE_LENGTH (type) <= 8);
- memset (buf, 0, sizeof buf);
- memcpy (buf, valbuf, std::min (TYPE_LENGTH (type), (ULONGEST) 8));
- regcache->cooked_write (regno, buf);
- }
- /* Push the arguments for an inferior function call, and return
- the updated value of the SP (Stack Pointer).
- All arguments are identical to the arguments used in
- amd64_windows_push_dummy_call. */
- static CORE_ADDR
- amd64_windows_push_arguments (struct regcache *regcache, int nargs,
- struct value **args, CORE_ADDR sp,
- function_call_return_method return_method)
- {
- int reg_idx = 0;
- int i;
- struct value **stack_args = XALLOCAVEC (struct value *, nargs);
- int num_stack_args = 0;
- int num_elements = 0;
- int element = 0;
- /* First, handle the arguments passed by pointer.
- These arguments are replaced by pointers to a copy we are making
- in inferior memory. So use a copy of the ARGS table, to avoid
- modifying the original one. */
- {
- struct value **args1 = XALLOCAVEC (struct value *, nargs);
- memcpy (args1, args, nargs * sizeof (struct value *));
- sp = amd64_windows_adjust_args_passed_by_pointer (args1, nargs, sp);
- args = args1;
- }
- /* Reserve a register for the "hidden" argument. */
- if (return_method == return_method_struct)
- reg_idx++;
- for (i = 0; i < nargs; i++)
- {
- struct type *type = value_type (args[i]);
- int len = TYPE_LENGTH (type);
- int on_stack_p = 1;
- if (reg_idx < ARRAY_SIZE (amd64_windows_dummy_call_integer_regs))
- {
- if (amd64_windows_passed_by_integer_register (type))
- {
- amd64_windows_store_arg_in_reg
- (regcache, args[i],
- amd64_windows_dummy_call_integer_regs[reg_idx]);
- on_stack_p = 0;
- reg_idx++;
- }
- else if (amd64_windows_passed_by_xmm_register (type))
- {
- amd64_windows_store_arg_in_reg
- (regcache, args[i], AMD64_XMM0_REGNUM + reg_idx);
- /* In case of varargs, these parameters must also be
- passed via the integer registers. */
- amd64_windows_store_arg_in_reg
- (regcache, args[i],
- amd64_windows_dummy_call_integer_regs[reg_idx]);
- on_stack_p = 0;
- reg_idx++;
- }
- }
- if (on_stack_p)
- {
- num_elements += ((len + 7) / 8);
- stack_args[num_stack_args++] = args[i];
- }
- }
- /* Allocate space for the arguments on the stack, keeping it
- aligned on a 16 byte boundary. */
- sp -= num_elements * 8;
- sp &= ~0xf;
- /* Write out the arguments to the stack. */
- for (i = 0; i < num_stack_args; i++)
- {
- struct type *type = value_type (stack_args[i]);
- const gdb_byte *valbuf = value_contents (stack_args[i]).data ();
- write_memory (sp + element * 8, valbuf, TYPE_LENGTH (type));
- element += ((TYPE_LENGTH (type) + 7) / 8);
- }
- return sp;
- }
- /* Implement the "push_dummy_call" gdbarch method. */
- static CORE_ADDR
- amd64_windows_push_dummy_call
- (struct gdbarch *gdbarch, struct value *function,
- struct regcache *regcache, CORE_ADDR bp_addr,
- int nargs, struct value **args, CORE_ADDR sp,
- function_call_return_method return_method, CORE_ADDR struct_addr)
- {
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- gdb_byte buf[8];
- /* Pass arguments. */
- sp = amd64_windows_push_arguments (regcache, nargs, args, sp,
- return_method);
- /* Pass "hidden" argument". */
- if (return_method == return_method_struct)
- {
- /* The "hidden" argument is passed throught the first argument
- register. */
- const int arg_regnum = amd64_windows_dummy_call_integer_regs[0];
- store_unsigned_integer (buf, 8, byte_order, struct_addr);
- regcache->cooked_write (arg_regnum, buf);
- }
- /* Reserve some memory on the stack for the integer-parameter
- registers, as required by the ABI. */
- sp -= ARRAY_SIZE (amd64_windows_dummy_call_integer_regs) * 8;
- /* Store return address. */
- sp -= 8;
- store_unsigned_integer (buf, 8, byte_order, bp_addr);
- write_memory (sp, buf, 8);
- /* Update the stack pointer... */
- store_unsigned_integer (buf, 8, byte_order, sp);
- regcache->cooked_write (AMD64_RSP_REGNUM, buf);
- /* ...and fake a frame pointer. */
- regcache->cooked_write (AMD64_RBP_REGNUM, buf);
- return sp + 16;
- }
- /* Implement the "return_value" gdbarch method for amd64-windows. */
- static enum return_value_convention
- amd64_windows_return_value (struct gdbarch *gdbarch, struct value *function,
- struct type *type, struct regcache *regcache,
- gdb_byte *readbuf, const gdb_byte *writebuf)
- {
- int len = TYPE_LENGTH (type);
- int regnum = -1;
- /* See if our value is returned through a register. If it is, then
- store the associated register number in REGNUM. */
- switch (type->code ())
- {
- case TYPE_CODE_FLT:
- /* floats, and doubles are returned via XMM0. */
- if (len == 4 || len == 8)
- regnum = AMD64_XMM0_REGNUM;
- break;
- case TYPE_CODE_ARRAY:
- /* __m128, __m128i and __m128d are returned via XMM0. */
- if (type->is_vector () && len == 16)
- {
- enum type_code code = TYPE_TARGET_TYPE (type)->code ();
- if (code == TYPE_CODE_INT || code == TYPE_CODE_FLT)
- {
- regnum = AMD64_XMM0_REGNUM;
- break;
- }
- }
- /* fall through */
- default:
- /* All other values that are 1, 2, 4 or 8 bytes long are returned
- via RAX. */
- if (len == 1 || len == 2 || len == 4 || len == 8)
- regnum = AMD64_RAX_REGNUM;
- else if (len == 16 && type->code () == TYPE_CODE_INT)
- regnum = AMD64_XMM0_REGNUM;
- break;
- }
- if (regnum < 0)
- {
- /* RAX contains the address where the return value has been stored. */
- if (readbuf)
- {
- ULONGEST addr;
- regcache_raw_read_unsigned (regcache, AMD64_RAX_REGNUM, &addr);
- read_memory (addr, readbuf, TYPE_LENGTH (type));
- }
- return RETURN_VALUE_ABI_RETURNS_ADDRESS;
- }
- else
- {
- /* Extract the return value from the register where it was stored. */
- if (readbuf)
- regcache->raw_read_part (regnum, 0, len, readbuf);
- if (writebuf)
- regcache->raw_write_part (regnum, 0, len, writebuf);
- return RETURN_VALUE_REGISTER_CONVENTION;
- }
- }
- /* Check that the code pointed to by PC corresponds to a call to
- __main, skip it if so. Return PC otherwise. */
- static CORE_ADDR
- amd64_skip_main_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
- {
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- gdb_byte op;
- target_read_memory (pc, &op, 1);
- if (op == 0xe8)
- {
- gdb_byte buf[4];
- if (target_read_memory (pc + 1, buf, sizeof buf) == 0)
- {
- struct bound_minimal_symbol s;
- CORE_ADDR call_dest;
- call_dest = pc + 5 + extract_signed_integer (buf, 4, byte_order);
- s = lookup_minimal_symbol_by_pc (call_dest);
- if (s.minsym != NULL
- && s.minsym->linkage_name () != NULL
- && strcmp (s.minsym->linkage_name (), "__main") == 0)
- pc += 5;
- }
- }
- return pc;
- }
- struct amd64_windows_frame_cache
- {
- /* ImageBase for the module. */
- CORE_ADDR image_base;
- /* Function start and end rva. */
- CORE_ADDR start_rva;
- CORE_ADDR end_rva;
- /* Next instruction to be executed. */
- CORE_ADDR pc;
- /* Current sp. */
- CORE_ADDR sp;
- /* Address of saved integer and xmm registers. */
- CORE_ADDR prev_reg_addr[16];
- CORE_ADDR prev_xmm_addr[16];
- /* These two next fields are set only for machine info frames. */
- /* Likewise for RIP. */
- CORE_ADDR prev_rip_addr;
- /* Likewise for RSP. */
- CORE_ADDR prev_rsp_addr;
- /* Address of the previous frame. */
- CORE_ADDR prev_sp;
- };
- /* Convert a Windows register number to gdb. */
- static const enum amd64_regnum amd64_windows_w2gdb_regnum[] =
- {
- AMD64_RAX_REGNUM,
- AMD64_RCX_REGNUM,
- AMD64_RDX_REGNUM,
- AMD64_RBX_REGNUM,
- AMD64_RSP_REGNUM,
- AMD64_RBP_REGNUM,
- AMD64_RSI_REGNUM,
- AMD64_RDI_REGNUM,
- AMD64_R8_REGNUM,
- AMD64_R9_REGNUM,
- AMD64_R10_REGNUM,
- AMD64_R11_REGNUM,
- AMD64_R12_REGNUM,
- AMD64_R13_REGNUM,
- AMD64_R14_REGNUM,
- AMD64_R15_REGNUM
- };
- /* Return TRUE iff PC is the range of the function corresponding to
- CACHE. */
- static int
- pc_in_range (CORE_ADDR pc, const struct amd64_windows_frame_cache *cache)
- {
- return (pc >= cache->image_base + cache->start_rva
- && pc < cache->image_base + cache->end_rva);
- }
- /* Try to recognize and decode an epilogue sequence.
- Return -1 if we fail to read the instructions for any reason.
- Return 1 if an epilogue sequence was recognized, 0 otherwise. */
- static int
- amd64_windows_frame_decode_epilogue (struct frame_info *this_frame,
- struct amd64_windows_frame_cache *cache)
- {
- /* According to MSDN an epilogue "must consist of either an add RSP,constant
- or lea RSP,constant[FPReg], followed by a series of zero or more 8-byte
- register pops and a return or a jmp".
- Furthermore, according to RtlVirtualUnwind, the complete list of
- epilog marker is:
- - ret [c3]
- - ret n [c2 imm16]
- - rep ret [f3 c3]
- - jmp imm8 | imm32 [eb rel8] or [e9 rel32]
- - jmp qword ptr imm32 - not handled
- - rex.w jmp reg [4X ff eY]
- */
- CORE_ADDR pc = cache->pc;
- CORE_ADDR cur_sp = cache->sp;
- struct gdbarch *gdbarch = get_frame_arch (this_frame);
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- gdb_byte op;
- gdb_byte rex;
- /* We don't care about the instruction deallocating the frame:
- if it hasn't been executed, the pc is still in the body,
- if it has been executed, the following epilog decoding will work. */
- /* First decode:
- - pop reg [41 58-5f] or [58-5f]. */
- while (1)
- {
- /* Read opcode. */
- if (target_read_memory (pc, &op, 1) != 0)
- return -1;
- if (op >= 0x40 && op <= 0x4f)
- {
- /* REX prefix. */
- rex = op;
- /* Read opcode. */
- if (target_read_memory (pc + 1, &op, 1) != 0)
- return -1;
- }
- else
- rex = 0;
- if (op >= 0x58 && op <= 0x5f)
- {
- /* pop reg */
- gdb_byte reg = (op & 0x0f) | ((rex & 1) << 3);
- cache->prev_reg_addr[amd64_windows_w2gdb_regnum[reg]] = cur_sp;
- cur_sp += 8;
- pc += rex ? 2 : 1;
- }
- else
- break;
- /* Allow the user to break this loop. This shouldn't happen as the
- number of consecutive pop should be small. */
- QUIT;
- }
- /* Then decode the marker. */
- /* Read opcode. */
- if (target_read_memory (pc, &op, 1) != 0)
- return -1;
- switch (op)
- {
- case 0xc3:
- /* Ret. */
- cache->prev_rip_addr = cur_sp;
- cache->prev_sp = cur_sp + 8;
- return 1;
- case 0xeb:
- {
- /* jmp rel8 */
- gdb_byte rel8;
- CORE_ADDR npc;
- if (target_read_memory (pc + 1, &rel8, 1) != 0)
- return -1;
- npc = pc + 2 + (signed char) rel8;
- /* If the jump is within the function, then this is not a marker,
- otherwise this is a tail-call. */
- return !pc_in_range (npc, cache);
- }
- case 0xec:
- {
- /* jmp rel32 */
- gdb_byte rel32[4];
- CORE_ADDR npc;
- if (target_read_memory (pc + 1, rel32, 4) != 0)
- return -1;
- npc = pc + 5 + extract_signed_integer (rel32, 4, byte_order);
- /* If the jump is within the function, then this is not a marker,
- otherwise this is a tail-call. */
- return !pc_in_range (npc, cache);
- }
- case 0xc2:
- {
- /* ret n */
- gdb_byte imm16[2];
- if (target_read_memory (pc + 1, imm16, 2) != 0)
- return -1;
- cache->prev_rip_addr = cur_sp;
- cache->prev_sp = cur_sp
- + extract_unsigned_integer (imm16, 4, byte_order);
- return 1;
- }
- case 0xf3:
- {
- /* rep; ret */
- gdb_byte op1;
- if (target_read_memory (pc + 2, &op1, 1) != 0)
- return -1;
- if (op1 != 0xc3)
- return 0;
- cache->prev_rip_addr = cur_sp;
- cache->prev_sp = cur_sp + 8;
- return 1;
- }
- case 0x40:
- case 0x41:
- case 0x42:
- case 0x43:
- case 0x44:
- case 0x45:
- case 0x46:
- case 0x47:
- case 0x48:
- case 0x49:
- case 0x4a:
- case 0x4b:
- case 0x4c:
- case 0x4d:
- case 0x4e:
- case 0x4f:
- /* Got a REX prefix, read next byte. */
- rex = op;
- if (target_read_memory (pc + 1, &op, 1) != 0)
- return -1;
- if (op == 0xff)
- {
- /* rex jmp reg */
- gdb_byte op1;
- if (target_read_memory (pc + 2, &op1, 1) != 0)
- return -1;
- return (op1 & 0xf8) == 0xe0;
- }
- else
- return 0;
- default:
- /* Not REX, so unknown. */
- return 0;
- }
- }
- /* Decode and execute unwind insns at UNWIND_INFO. */
- static void
- amd64_windows_frame_decode_insns (struct frame_info *this_frame,
- struct amd64_windows_frame_cache *cache,
- CORE_ADDR unwind_info)
- {
- CORE_ADDR save_addr = 0;
- CORE_ADDR cur_sp = cache->sp;
- struct gdbarch *gdbarch = get_frame_arch (this_frame);
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- int first = 1;
- /* There are at least 3 possibilities to share an unwind info entry:
- 1. Two different runtime_function entries (in .pdata) can point to the
- same unwind info entry. There is no such indication while unwinding,
- so we don't really care about that case. We suppose this scheme is
- used to save memory when the unwind entries are exactly the same.
- 2. Chained unwind_info entries, with no unwind codes (no prologue).
- There is a major difference with the previous case: the pc range for
- the function is different (in case 1, the pc range comes from the
- runtime_function entry; in case 2, the pc range for the chained entry
- comes from the first unwind entry). Case 1 cannot be used instead as
- the pc is not in the prologue. This case is officially documented.
- (There might be unwind code in the first unwind entry to handle
- additional unwinding). GCC (at least until gcc 5.0) doesn't chain
- entries.
- 3. Undocumented unwind info redirection. Hard to know the exact purpose,
- so it is considered as a memory optimization of case 2.
- */
- if (unwind_info & 1)
- {
- /* Unofficially documented unwind info redirection, when UNWIND_INFO
- address is odd (http://www.codemachine.com/article_x64deepdive.html).
- */
- struct external_pex64_runtime_function d;
- if (target_read_memory (cache->image_base + (unwind_info & ~1),
- (gdb_byte *) &d, sizeof (d)) != 0)
- return;
- cache->start_rva
- = extract_unsigned_integer (d.rva_BeginAddress, 4, byte_order);
- cache->end_rva
- = extract_unsigned_integer (d.rva_EndAddress, 4, byte_order);
- unwind_info
- = extract_unsigned_integer (d.rva_UnwindData, 4, byte_order);
- }
- while (1)
- {
- struct external_pex64_unwind_info ex_ui;
- /* There are at most 256 16-bit unwind insns. */
- gdb_byte insns[2 * 256];
- gdb_byte *p;
- gdb_byte *end_insns;
- unsigned char codes_count;
- unsigned char frame_reg;
- CORE_ADDR start;
- /* Read and decode header. */
- if (target_read_memory (cache->image_base + unwind_info,
- (gdb_byte *) &ex_ui, sizeof (ex_ui)) != 0)
- return;
- frame_debug_printf ("%s: ver: %02x, plgsz: %02x, cnt: %02x, frame: %02x",
- paddress (gdbarch, unwind_info),
- ex_ui.Version_Flags, ex_ui.SizeOfPrologue,
- ex_ui.CountOfCodes, ex_ui.FrameRegisterOffset);
- /* Check version. */
- if (PEX64_UWI_VERSION (ex_ui.Version_Flags) != 1
- && PEX64_UWI_VERSION (ex_ui.Version_Flags) != 2)
- return;
- start = cache->image_base + cache->start_rva;
- if (first
- && !(cache->pc >= start && cache->pc < start + ex_ui.SizeOfPrologue))
- {
- /* We want to detect if the PC points to an epilogue. This needs
- to be checked only once, and an epilogue can be anywhere but in
- the prologue. If so, the epilogue detection+decoding function is
- sufficient. Otherwise, the unwinder will consider that the PC
- is in the body of the function and will need to decode unwind
- info. */
- if (amd64_windows_frame_decode_epilogue (this_frame, cache) == 1)
- return;
- /* Not in an epilog. Clear possible side effects. */
- memset (cache->prev_reg_addr, 0, sizeof (cache->prev_reg_addr));
- }
- codes_count = ex_ui.CountOfCodes;
- frame_reg = PEX64_UWI_FRAMEREG (ex_ui.FrameRegisterOffset);
- if (frame_reg != 0)
- {
- /* According to msdn:
- If an FP reg is used, then any unwind code taking an offset must
- only be used after the FP reg is established in the prolog. */
- gdb_byte buf[8];
- int frreg = amd64_windows_w2gdb_regnum[frame_reg];
- get_frame_register (this_frame, frreg, buf);
- save_addr = extract_unsigned_integer (buf, 8, byte_order);
- frame_debug_printf (" frame_reg=%s, val=%s",
- gdbarch_register_name (gdbarch, frreg),
- paddress (gdbarch, save_addr));
- }
- /* Read opcodes. */
- if (codes_count != 0
- && target_read_memory (cache->image_base + unwind_info
- + sizeof (ex_ui),
- insns, codes_count * 2) != 0)
- return;
- end_insns = &insns[codes_count * 2];
- p = insns;
- /* Skip opcodes 6 of version 2. This opcode is not documented. */
- if (PEX64_UWI_VERSION (ex_ui.Version_Flags) == 2)
- {
- for (; p < end_insns; p += 2)
- if (PEX64_UNWCODE_CODE (p[1]) != 6)
- break;
- }
- for (; p < end_insns; p += 2)
- {
- int reg;
- /* Virtually execute the operation if the pc is after the
- corresponding instruction (that does matter in case of break
- within the prologue). Note that for chained info (!first), the
- prologue has been fully executed. */
- if (cache->pc >= start + p[0] || cache->pc < start)
- {
- frame_debug_printf (" op #%u: off=0x%02x, insn=0x%02x",
- (unsigned) (p - insns), p[0], p[1]);
- /* If there is no frame registers defined, the current value of
- rsp is used instead. */
- if (frame_reg == 0)
- save_addr = cur_sp;
- reg = -1;
- switch (PEX64_UNWCODE_CODE (p[1]))
- {
- case UWOP_PUSH_NONVOL:
- /* Push pre-decrements RSP. */
- reg = amd64_windows_w2gdb_regnum[PEX64_UNWCODE_INFO (p[1])];
- cache->prev_reg_addr[reg] = cur_sp;
- cur_sp += 8;
- break;
- case UWOP_ALLOC_LARGE:
- if (PEX64_UNWCODE_INFO (p[1]) == 0)
- cur_sp +=
- 8 * extract_unsigned_integer (p + 2, 2, byte_order);
- else if (PEX64_UNWCODE_INFO (p[1]) == 1)
- cur_sp += extract_unsigned_integer (p + 2, 4, byte_order);
- else
- return;
- break;
- case UWOP_ALLOC_SMALL:
- cur_sp += 8 + 8 * PEX64_UNWCODE_INFO (p[1]);
- break;
- case UWOP_SET_FPREG:
- cur_sp = save_addr
- - PEX64_UWI_FRAMEOFF (ex_ui.FrameRegisterOffset) * 16;
- break;
- case UWOP_SAVE_NONVOL:
- reg = amd64_windows_w2gdb_regnum[PEX64_UNWCODE_INFO (p[1])];
- cache->prev_reg_addr[reg] = save_addr
- + 8 * extract_unsigned_integer (p + 2, 2, byte_order);
- break;
- case UWOP_SAVE_NONVOL_FAR:
- reg = amd64_windows_w2gdb_regnum[PEX64_UNWCODE_INFO (p[1])];
- cache->prev_reg_addr[reg] = save_addr
- + 8 * extract_unsigned_integer (p + 2, 4, byte_order);
- break;
- case UWOP_SAVE_XMM128:
- cache->prev_xmm_addr[PEX64_UNWCODE_INFO (p[1])] =
- save_addr
- - 16 * extract_unsigned_integer (p + 2, 2, byte_order);
- break;
- case UWOP_SAVE_XMM128_FAR:
- cache->prev_xmm_addr[PEX64_UNWCODE_INFO (p[1])] =
- save_addr
- - 16 * extract_unsigned_integer (p + 2, 4, byte_order);
- break;
- case UWOP_PUSH_MACHFRAME:
- if (PEX64_UNWCODE_INFO (p[1]) == 0)
- {
- cache->prev_rip_addr = cur_sp + 0;
- cache->prev_rsp_addr = cur_sp + 24;
- cur_sp += 40;
- }
- else if (PEX64_UNWCODE_INFO (p[1]) == 1)
- {
- cache->prev_rip_addr = cur_sp + 8;
- cache->prev_rsp_addr = cur_sp + 32;
- cur_sp += 48;
- }
- else
- return;
- break;
- default:
- return;
- }
- /* Display address where the register was saved. */
- if (reg >= 0)
- frame_debug_printf (" [reg %s at %s]",
- gdbarch_register_name (gdbarch, reg),
- paddress (gdbarch,
- cache->prev_reg_addr[reg]));
- }
- /* Adjust with the length of the opcode. */
- switch (PEX64_UNWCODE_CODE (p[1]))
- {
- case UWOP_PUSH_NONVOL:
- case UWOP_ALLOC_SMALL:
- case UWOP_SET_FPREG:
- case UWOP_PUSH_MACHFRAME:
- break;
- case UWOP_ALLOC_LARGE:
- if (PEX64_UNWCODE_INFO (p[1]) == 0)
- p += 2;
- else if (PEX64_UNWCODE_INFO (p[1]) == 1)
- p += 4;
- else
- return;
- break;
- case UWOP_SAVE_NONVOL:
- case UWOP_SAVE_XMM128:
- p += 2;
- break;
- case UWOP_SAVE_NONVOL_FAR:
- case UWOP_SAVE_XMM128_FAR:
- p += 4;
- break;
- default:
- return;
- }
- }
- if (PEX64_UWI_FLAGS (ex_ui.Version_Flags) != UNW_FLAG_CHAININFO)
- {
- /* End of unwind info. */
- break;
- }
- else
- {
- /* Read the chained unwind info. */
- struct external_pex64_runtime_function d;
- CORE_ADDR chain_vma;
- /* Not anymore the first entry. */
- first = 0;
- /* Stay aligned on word boundary. */
- chain_vma = cache->image_base + unwind_info
- + sizeof (ex_ui) + ((codes_count + 1) & ~1) * 2;
- if (target_read_memory (chain_vma, (gdb_byte *) &d, sizeof (d)) != 0)
- return;
- /* Decode begin/end. This may be different from .pdata index, as
- an unwind info may be shared by several functions (in particular
- if many functions have the same prolog and handler. */
- cache->start_rva =
- extract_unsigned_integer (d.rva_BeginAddress, 4, byte_order);
- cache->end_rva =
- extract_unsigned_integer (d.rva_EndAddress, 4, byte_order);
- unwind_info =
- extract_unsigned_integer (d.rva_UnwindData, 4, byte_order);
- frame_debug_printf ("next in chain: unwind_data=%s, start_rva=%s, "
- "end_rva=%s",
- paddress (gdbarch, unwind_info),
- paddress (gdbarch, cache->start_rva),
- paddress (gdbarch, cache->end_rva));
- }
- /* Allow the user to break this loop. */
- QUIT;
- }
- /* PC is saved by the call. */
- if (cache->prev_rip_addr == 0)
- cache->prev_rip_addr = cur_sp;
- cache->prev_sp = cur_sp + 8;
- frame_debug_printf (" prev_sp: %s, prev_pc @%s",
- paddress (gdbarch, cache->prev_sp),
- paddress (gdbarch, cache->prev_rip_addr));
- }
- /* Find SEH unwind info for PC, returning 0 on success.
- UNWIND_INFO is set to the rva of unwind info address, IMAGE_BASE
- to the base address of the corresponding image, and START_RVA
- to the rva of the function containing PC. */
- static int
- amd64_windows_find_unwind_info (struct gdbarch *gdbarch, CORE_ADDR pc,
- CORE_ADDR *unwind_info,
- CORE_ADDR *image_base,
- CORE_ADDR *start_rva,
- CORE_ADDR *end_rva)
- {
- struct obj_section *sec;
- pe_data_type *pe;
- IMAGE_DATA_DIRECTORY *dir;
- struct objfile *objfile;
- unsigned long lo, hi;
- CORE_ADDR base;
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- /* Get the corresponding exception directory. */
- sec = find_pc_section (pc);
- if (sec == NULL)
- return -1;
- objfile = sec->objfile;
- pe = pe_data (sec->objfile->obfd);
- dir = &pe->pe_opthdr.DataDirectory[PE_EXCEPTION_TABLE];
- base = pe->pe_opthdr.ImageBase + objfile->text_section_offset ();
- *image_base = base;
- /* Find the entry.
- Note: This does not handle dynamically added entries (for JIT
- engines). For this, we would need to ask the kernel directly,
- which means getting some info from the native layer. For the
- rest of the code, however, it's probably faster to search
- the entry ourselves. */
- lo = 0;
- hi = dir->Size / sizeof (struct external_pex64_runtime_function);
- *unwind_info = 0;
- while (lo <= hi)
- {
- unsigned long mid = lo + (hi - lo) / 2;
- struct external_pex64_runtime_function d;
- CORE_ADDR sa, ea;
- if (target_read_memory (base + dir->VirtualAddress + mid * sizeof (d),
- (gdb_byte *) &d, sizeof (d)) != 0)
- return -1;
- sa = extract_unsigned_integer (d.rva_BeginAddress, 4, byte_order);
- ea = extract_unsigned_integer (d.rva_EndAddress, 4, byte_order);
- if (pc < base + sa)
- hi = mid - 1;
- else if (pc >= base + ea)
- lo = mid + 1;
- else if (pc >= base + sa && pc < base + ea)
- {
- /* Got it. */
- *start_rva = sa;
- *end_rva = ea;
- *unwind_info =
- extract_unsigned_integer (d.rva_UnwindData, 4, byte_order);
- break;
- }
- else
- break;
- }
- frame_debug_printf ("image_base=%s, unwind_data=%s",
- paddress (gdbarch, base),
- paddress (gdbarch, *unwind_info));
- return 0;
- }
- /* Fill THIS_CACHE using the native amd64-windows unwinding data
- for THIS_FRAME. */
- static struct amd64_windows_frame_cache *
- amd64_windows_frame_cache (struct frame_info *this_frame, void **this_cache)
- {
- struct gdbarch *gdbarch = get_frame_arch (this_frame);
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- struct amd64_windows_frame_cache *cache;
- gdb_byte buf[8];
- CORE_ADDR pc;
- CORE_ADDR unwind_info = 0;
- if (*this_cache)
- return (struct amd64_windows_frame_cache *) *this_cache;
- cache = FRAME_OBSTACK_ZALLOC (struct amd64_windows_frame_cache);
- *this_cache = cache;
- /* Get current PC and SP. */
- pc = get_frame_pc (this_frame);
- get_frame_register (this_frame, AMD64_RSP_REGNUM, buf);
- cache->sp = extract_unsigned_integer (buf, 8, byte_order);
- cache->pc = pc;
- if (amd64_windows_find_unwind_info (gdbarch, pc, &unwind_info,
- &cache->image_base,
- &cache->start_rva,
- &cache->end_rva))
- return cache;
- if (unwind_info == 0)
- {
- /* Assume a leaf function. */
- cache->prev_sp = cache->sp + 8;
- cache->prev_rip_addr = cache->sp;
- }
- else
- {
- /* Decode unwind insns to compute saved addresses. */
- amd64_windows_frame_decode_insns (this_frame, cache, unwind_info);
- }
- return cache;
- }
- /* Implement the "prev_register" method of struct frame_unwind
- using the standard Windows x64 SEH info. */
- static struct value *
- amd64_windows_frame_prev_register (struct frame_info *this_frame,
- void **this_cache, int regnum)
- {
- struct gdbarch *gdbarch = get_frame_arch (this_frame);
- struct amd64_windows_frame_cache *cache =
- amd64_windows_frame_cache (this_frame, this_cache);
- CORE_ADDR prev;
- frame_debug_printf ("%s for sp=%s",
- gdbarch_register_name (gdbarch, regnum),
- paddress (gdbarch, cache->prev_sp));
- if (regnum >= AMD64_XMM0_REGNUM && regnum <= AMD64_XMM0_REGNUM + 15)
- prev = cache->prev_xmm_addr[regnum - AMD64_XMM0_REGNUM];
- else if (regnum == AMD64_RSP_REGNUM)
- {
- prev = cache->prev_rsp_addr;
- if (prev == 0)
- return frame_unwind_got_constant (this_frame, regnum, cache->prev_sp);
- }
- else if (regnum >= AMD64_RAX_REGNUM && regnum <= AMD64_R15_REGNUM)
- prev = cache->prev_reg_addr[regnum - AMD64_RAX_REGNUM];
- else if (regnum == AMD64_RIP_REGNUM)
- prev = cache->prev_rip_addr;
- else
- prev = 0;
- if (prev != 0)
- frame_debug_printf (" -> at %s", paddress (gdbarch, prev));
- if (prev)
- {
- /* Register was saved. */
- return frame_unwind_got_memory (this_frame, regnum, prev);
- }
- else
- {
- /* Register is either volatile or not modified. */
- return frame_unwind_got_register (this_frame, regnum, regnum);
- }
- }
- /* Implement the "this_id" method of struct frame_unwind using
- the standard Windows x64 SEH info. */
- static void
- amd64_windows_frame_this_id (struct frame_info *this_frame, void **this_cache,
- struct frame_id *this_id)
- {
- struct amd64_windows_frame_cache *cache =
- amd64_windows_frame_cache (this_frame, this_cache);
- *this_id = frame_id_build (cache->prev_sp,
- cache->image_base + cache->start_rva);
- }
- /* Windows x64 SEH unwinder. */
- static const struct frame_unwind amd64_windows_frame_unwind =
- {
- "amd64 windows",
- NORMAL_FRAME,
- default_frame_unwind_stop_reason,
- &amd64_windows_frame_this_id,
- &amd64_windows_frame_prev_register,
- NULL,
- default_frame_sniffer
- };
- /* Implement the "skip_prologue" gdbarch method. */
- static CORE_ADDR
- amd64_windows_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
- {
- CORE_ADDR func_addr;
- CORE_ADDR unwind_info = 0;
- CORE_ADDR image_base, start_rva, end_rva;
- struct external_pex64_unwind_info ex_ui;
- /* Use prologue size from unwind info. */
- if (amd64_windows_find_unwind_info (gdbarch, pc, &unwind_info,
- &image_base, &start_rva, &end_rva) == 0)
- {
- if (unwind_info == 0)
- {
- /* Leaf function. */
- return pc;
- }
- else if (target_read_memory (image_base + unwind_info,
- (gdb_byte *) &ex_ui, sizeof (ex_ui)) == 0
- && PEX64_UWI_VERSION (ex_ui.Version_Flags) == 1)
- return std::max (pc, image_base + start_rva + ex_ui.SizeOfPrologue);
- }
- /* See if we can determine the end of the prologue via the symbol
- table. If so, then return either the PC, or the PC after
- the prologue, whichever is greater. */
- if (find_pc_partial_function (pc, NULL, &func_addr, NULL))
- {
- CORE_ADDR post_prologue_pc
- = skip_prologue_using_sal (gdbarch, func_addr);
- if (post_prologue_pc != 0)
- return std::max (pc, post_prologue_pc);
- }
- return pc;
- }
- /* Check Win64 DLL jmp trampolines and find jump destination. */
- static CORE_ADDR
- amd64_windows_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
- {
- CORE_ADDR destination = 0;
- struct gdbarch *gdbarch = get_frame_arch (frame);
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- /* Check for jmp *<offset>(%rip) (jump near, absolute indirect (/4)). */
- if (pc && read_memory_unsigned_integer (pc, 2, byte_order) == 0x25ff)
- {
- /* Get opcode offset and see if we can find a reference in our data. */
- ULONGEST offset
- = read_memory_unsigned_integer (pc + 2, 4, byte_order);
- /* Get address of function pointer at end of pc. */
- CORE_ADDR indirect_addr = pc + offset + 6;
- struct minimal_symbol *indsym
- = (indirect_addr
- ? lookup_minimal_symbol_by_pc (indirect_addr).minsym
- : NULL);
- const char *symname = indsym ? indsym->linkage_name () : NULL;
- if (symname)
- {
- if (startswith (symname, "__imp_")
- || startswith (symname, "_imp_"))
- destination
- = read_memory_unsigned_integer (indirect_addr, 8, byte_order);
- }
- }
- return destination;
- }
- /* Implement the "auto_wide_charset" gdbarch method. */
- static const char *
- amd64_windows_auto_wide_charset (void)
- {
- return "UTF-16";
- }
- /* Common parts for gdbarch initialization for Windows and Cygwin on AMD64. */
- static void
- amd64_windows_init_abi_common (gdbarch_info info, struct gdbarch *gdbarch)
- {
- i386_gdbarch_tdep *tdep = (i386_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- /* The dwarf2 unwinder (appended very early by i386_gdbarch_init) is
- preferred over the SEH one. The reasons are:
- - binaries without SEH but with dwarf2 debug info are correctly handled
- (although they aren't ABI compliant, gcc before 4.7 didn't emit SEH
- info).
- - dwarf3 DW_OP_call_frame_cfa is correctly handled (it can only be
- handled if the dwarf2 unwinder is used).
- The call to amd64_init_abi appends default unwinders, that aren't
- compatible with the SEH one.
- */
- frame_unwind_append_unwinder (gdbarch, &amd64_windows_frame_unwind);
- amd64_init_abi (info, gdbarch,
- amd64_target_description (X86_XSTATE_SSE_MASK, false));
- /* Function calls. */
- set_gdbarch_push_dummy_call (gdbarch, amd64_windows_push_dummy_call);
- set_gdbarch_return_value (gdbarch, amd64_windows_return_value);
- set_gdbarch_skip_main_prologue (gdbarch, amd64_skip_main_prologue);
- set_gdbarch_skip_trampoline_code (gdbarch,
- amd64_windows_skip_trampoline_code);
- set_gdbarch_skip_prologue (gdbarch, amd64_windows_skip_prologue);
- tdep->gregset_reg_offset = amd64_windows_gregset_reg_offset;
- tdep->gregset_num_regs = ARRAY_SIZE (amd64_windows_gregset_reg_offset);
- tdep->sizeof_gregset = AMD64_WINDOWS_SIZEOF_GREGSET;
- tdep->sizeof_fpregset = 0;
- /* Core file support. */
- set_gdbarch_core_xfer_shared_libraries
- (gdbarch, windows_core_xfer_shared_libraries);
- set_gdbarch_core_pid_to_str (gdbarch, windows_core_pid_to_str);
- set_gdbarch_auto_wide_charset (gdbarch, amd64_windows_auto_wide_charset);
- }
- /* gdbarch initialization for Windows on AMD64. */
- static void
- amd64_windows_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
- {
- amd64_windows_init_abi_common (info, gdbarch);
- windows_init_abi (info, gdbarch);
- /* On Windows, "long"s are only 32bit. */
- set_gdbarch_long_bit (gdbarch, 32);
- }
- /* gdbarch initialization for Cygwin on AMD64. */
- static void
- amd64_cygwin_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
- {
- amd64_windows_init_abi_common (info, gdbarch);
- cygwin_init_abi (info, gdbarch);
- }
- static gdb_osabi
- amd64_windows_osabi_sniffer (bfd *abfd)
- {
- const char *target_name = bfd_get_target (abfd);
- if (!streq (target_name, "pei-x86-64"))
- return GDB_OSABI_UNKNOWN;
- if (is_linked_with_cygwin_dll (abfd))
- return GDB_OSABI_CYGWIN;
- return GDB_OSABI_WINDOWS;
- }
- static enum gdb_osabi
- amd64_cygwin_core_osabi_sniffer (bfd *abfd)
- {
- const char *target_name = bfd_get_target (abfd);
- /* Cygwin uses elf core dumps. Do not claim all ELF executables,
- check whether there is a .reg section of proper size. */
- if (strcmp (target_name, "elf64-x86-64") == 0)
- {
- asection *section = bfd_get_section_by_name (abfd, ".reg");
- if (section != nullptr
- && bfd_section_size (section) == AMD64_WINDOWS_SIZEOF_GREGSET)
- return GDB_OSABI_CYGWIN;
- }
- return GDB_OSABI_UNKNOWN;
- }
- void _initialize_amd64_windows_tdep ();
- void
- _initialize_amd64_windows_tdep ()
- {
- gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64, GDB_OSABI_WINDOWS,
- amd64_windows_init_abi);
- gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64, GDB_OSABI_CYGWIN,
- amd64_cygwin_init_abi);
- gdbarch_register_osabi_sniffer (bfd_arch_i386, bfd_target_coff_flavour,
- amd64_windows_osabi_sniffer);
- /* Cygwin uses elf core dumps. */
- gdbarch_register_osabi_sniffer (bfd_arch_i386, bfd_target_elf_flavour,
- amd64_cygwin_core_osabi_sniffer);
- }
|