This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [RFA] Add Windows x64 SEH unwinder


> From: Tristan Gingold <gingold@adacore.com>
> Date: Fri, 15 Jun 2012 10:09:56 +0200
> 
> Hi,
> 
> the Windows x64 ABI specifies unwind data info in order to unwind
> frames for propagating exceptions or getting back traces.  GCC emits
> this infos since version 4.7
> 
> This patch adds an unwinder that reads these data.  The main
> advantage is that gdb is now able to unwind through code compiled
> with other compilers (and through system libraries).
> 
> I haven't run the gdb testsuite on Windows x64 (I don't know if this
> is doable), but I have manually tested it on a few executables,
> including gdb itself.
> 
> Comments are welcome.

The amd64 codebase consistently uses the amd64_-prefix for structures,
variables and functions.  If this is effectively *the* unwinder for
64-bit windows, I'd recommend "amd64_windows_".  If you expect more
Windows-specfic unwinders (or think amd64_windows_ is too long)
"amd64_seh_" might be a good alternative.

> diff --git a/gdb/amd64-windows-tdep.c b/gdb/amd64-windows-tdep.c
> index 4a40f47..7070e06 100644
> --- a/gdb/amd64-windows-tdep.c
> +++ b/gdb/amd64-windows-tdep.c
> @@ -23,6 +23,12 @@
>  #include "gdbtypes.h"
>  #include "gdbcore.h"
>  #include "regcache.h"
> +#include "objfiles.h"
> +#include "frame-unwind.h"
> +#include "coff/internal.h"
> +#include "coff/i386.h"
> +#include "coff/pe.h"
> +#include "libcoff.h"
>  
>  /* The registers used to pass integer arguments during a function call.  */
>  static int amd64_windows_dummy_call_integer_regs[] =
> @@ -153,6 +159,588 @@ amd64_skip_main_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
>    return pc;
>  }
>  
> +struct x64_frame_cache
> +{
> +  CORE_ADDR image_base;		/* ImageBase for the module.  */
> +  CORE_ADDR start_address;	/* Function start rva.  */
> +  CORE_ADDR pc;			/* Next instruction to be executed.  */
> +  CORE_ADDR sp;			/* Current sp.  */
> +
> +  CORE_ADDR prev_reg_addr[16];	/* Address of saved registers.  */
> +  CORE_ADDR prev_xmm_addr[16];	/* Likewise for xmm registers.  */
> +  /* These two next fields are set only for machine info frames.  */
> +  CORE_ADDR prev_rip_addr;	/* Likewise for RIP.  */
> +  CORE_ADDR prev_rsp_addr;	/* Likewise for RSP.  */
> +  CORE_ADDR prev_sp;		/* Address of the previous frame.  */
> +};
> +
> +/* Convert a Windows register number to gdb.  */
> +static const enum amd64_regnum x64_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
> +};
> +
> +/* Try to recognize and decode an epilogue sequence.  */
> +
> +static int
> +x64_frame_decode_epilogue (struct frame_info *this_frame,
> +			   struct x64_frame_cache *cache)
> +{
> +  /* Not in a prologue, so maybe in an epilogue.  For the rules, cf
> +     http://msdn.microsoft.com/en-us/library/tawsa7cb.aspx
> +     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 jmp reg		[4X ff eY]
> +     I would add:
> +     -  pop reg                 [41 58-5f] or [58-5f]
> +
> +     We don't care about the instruction that deallocate the frame:
> +     if it hasn't been executed, we can safely decode the insns,
> +     if it has been executed, the following epilog decoding will
> +     work.
> +  */
> +  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);
> +
> +  while (1)
> +    {
> +      gdb_byte op;
> +      gdb_byte rex;
> +
> +      if (target_read_memory (pc, &op, 1) != 0)
> +	return -1;
> +
> +      if (op == 0xc3)
> +	{
> +	  /* Ret.  */
> +	  cache->prev_rip_addr = cur_sp;
> +	  cache->prev_sp = cur_sp + 8;
> +	  return 1;
> +	}
> +      else if (op == 0xeb)
> +	{
> +	  /* jmp rel8  */
> +	  gdb_byte rel8;
> +
> +	  if (target_read_memory (pc + 1, &rel8, 1) != 0)
> +	    return -1;
> +	  pc = pc + 2 + (signed char)rel8;
> +	}
> +      else if (op == 0xec)
> +	{
> +	  /* jmp rel32  */
> +	  gdb_byte rel32[4];
> +
> +	  if (target_read_memory (pc + 1, rel32, 4) != 0)
> +	    return -1;
> +	  pc = pc + 5 + extract_signed_integer (rel32, 4, byte_order);
> +	}
> +      else if (op >= 0x58 && op <= 0x5f)
> +	{
> +	  /* pop reg  */
> +	  cache->prev_reg_addr[x64_w2gdb_regnum[op & 0x0f]] = cur_sp;
> +	  cur_sp += 8;
> +	}
> +      else if (op == 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;
> +	}
> +      else if (op == 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;
> +	}
> +      else if (op < 0x40 || op > 0x4f)
> +	{
> +	  /* Not REX, so unknown.  */
> +	  return 0;
> +	}
> +
> +      /* Got a REX prefix, read next byte.  */
> +      rex = op;
> +      if (target_read_memory (pc + 1, &op, 1) != 0)
> +	return -1;
> +
> +      if (op >= 0x58 && op <= 0x5f)
> +	{
> +	  /* pop reg  */
> +	  unsigned int reg;
> +
> +	  reg = (op & 0x0f) | ((rex & 1) << 3);
> +	  cache->prev_reg_addr[x64_w2gdb_regnum[reg]] = cur_sp;
> +	  cur_sp += 8;
> +	}
> +      else if (op == 0xff)
> +	{
> +	  /* rex jmp reg  */
> +	  gdb_byte op1;
> +	  unsigned int reg;
> +	  gdb_byte buf[8];
> +
> +	  if (target_read_memory (pc + 2, &op1, 1) != 0)
> +	    return -1;
> +	  if ((op1 & 0xf8) != 0xe0)
> +	    return 0;
> +	  reg = (op1 & 0x0f) | ((rex & 1) << 3);
> +
> +	  get_frame_register (this_frame, x64_w2gdb_regnum[reg], buf);
> +	  pc = extract_unsigned_integer (buf, 8, byte_order);
> +	}
> +      else
> +	return 0;
> +
> +      /* Allow the user to break this loop.  */
> +      if (quit_flag)
> +	return 0;
> +    }
> +}
> +
> +/* Decode and execute unwind insns at UNWIND_INFO.  */
> +
> +static void
> +x64_frame_decode_insns (struct frame_info *this_frame,
> +			struct x64_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 j;
> +
> +  for (j = 0; ; j++)
> +    {
> +      struct external_pex64_unwind_info ex_ui;
> +      gdb_byte insns[2 * 256];
> +      gdb_byte *p;
> +      gdb_byte *end_insns;
> +      unsigned char codes_count;
> +      unsigned char frame_reg;
> +      unsigned char frame_off;
> +
> +      /* Read and decode header.  */
> +      if (target_read_memory (cache->image_base + unwind_info,
> +			      (char *) &ex_ui, sizeof (ex_ui)) != 0)
> +	return;
> +
> +      if (unwind_debug)
> +	fprintf_unfiltered
> +	  (gdb_stdlog,
> +	   "x64_frame_play_insn: "
> +	   "%s: ver: %02x, plgsz: %02x, cnt: %02x, frame: %02x\n",
> +	   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)
> +	return;
> +
> +      if (j == 0
> +	  && (cache->pc >=
> +	      cache->image_base + cache->start_address + ex_ui.SizeOfPrologue))
> +	{
> +	  /* Not in the prologue; try to decode an epilog.  */
> +	  if (x64_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 the the FP reg is established in the prolog.  */
> +	  gdb_byte buf[8];
> +	  int frreg = x64_w2gdb_regnum[frame_reg];
> +
> +	  get_frame_register (this_frame, frreg, buf);
> +	  save_addr = extract_unsigned_integer (buf, 8, byte_order);
> +
> +	  if (unwind_debug)
> +	    fprintf_unfiltered (gdb_stdlog, "   frame_reg=%s, val=%s\n",
> +				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];
> +      for (p = insns; p < end_insns; p += 2)
> +	{
> +	  int reg;
> +
> +	  if (unwind_debug)
> +	    fprintf_unfiltered
> +	      (gdb_stdlog, "   op #%u: off=0x%02x, insn=0x%02x\n",
> +	       (unsigned) (p - insns), p[0], p[1]);
> +
> +	  /* Virtually execute the operation.  */
> +	  if (cache->pc >= cache->image_base + cache->start_address + p[0])
> +	    {
> +	      /* If there is no frame registers defined, the current value of
> +		 rsp is used instead.  */
> +	      if (frame_reg == 0)
> +		save_addr = cur_sp;
> +
> +	      switch (PEX64_UNWCODE_CODE (p[1]))
> +		{
> +		case UWOP_PUSH_NONVOL:
> +		  /* Push pre-decrements RSP.  */
> +		  reg = x64_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 = x64_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 = x64_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
> +		    + 8 * 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
> +		    + 8 * 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;
> +		}
> +	    }
> +
> +	  /* 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)
> +	break;
> +      else
> +	{
> +	  /* Read the chained unwind info.  */
> +	  struct external_pex64_runtime_function d;
> +	  CORE_ADDR chain_vma;
> +
> +	  chain_vma = cache->image_base + unwind_info
> +	    + sizeof (ex_ui) + ((codes_count + 1) & ~1) * 2 + 8;
> +
> +	  if (target_read_memory (chain_vma, (char *) &d, sizeof (d)) != 0)
> +	    return;
> +
> +	  cache->start_address =
> +	    extract_unsigned_integer (d.rva_BeginAddress, 4, byte_order);
> +	  unwind_info =
> +	    extract_unsigned_integer (d.rva_EndAddress, 4, byte_order);
> +	}
> +
> +      /* Allow the user to break this loop.  */
> +      if (quit_flag)
> +	return;
> +    }
> +  /* PC is saved by the call.  */
> +  if (cache->prev_rip_addr == 0)
> +    cache->prev_rip_addr = cur_sp;
> +  cache->prev_sp = cur_sp + 8;
> +
> +  if (unwind_debug)
> +    fprintf_unfiltered (gdb_stdlog, "   prev_sp: %s, prev_pc @%s\n",
> +			paddress (gdbarch, cache->prev_sp),
> +			paddress (gdbarch, cache->prev_rip_addr));
> +}
> +
> +static struct x64_frame_cache *
> +x64_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 x64_frame_cache *cache;
> +  char buf[8];
> +  struct obj_section *sec;
> +  pe_data_type *pe;
> +  IMAGE_DATA_DIRECTORY *dir;
> +  CORE_ADDR image_base;
> +  CORE_ADDR pc;
> +  struct objfile *objfile;
> +  unsigned long lo, hi;
> +  CORE_ADDR unwind_info;
> +
> +  if (*this_cache)
> +    return *this_cache;
> +
> +  cache = FRAME_OBSTACK_ZALLOC (struct x64_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;
> +
> +  /* Get the corresponding exception directory.  */
> +  sec = find_pc_section (pc);
> +  if (unwind_debug)
> +    fprintf_unfiltered (gdb_stdlog, "x64_frame_cache: pc=%s, sp=%s, sec=%p\n",
> +			paddress (gdbarch, pc),
> +			paddress (gdbarch, cache->sp), sec);
> +  if (sec == NULL)
> +    return cache;
> +  objfile = sec->objfile;
> +  pe = pe_data (sec->objfile->obfd);
> +  dir = &pe->pe_opthdr.DataDirectory[PE_EXCEPTION_TABLE];
> +
> +  image_base = pe->pe_opthdr.ImageBase
> +    + ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
> +  cache->image_base = image_base;
> +
> +  if (unwind_debug)
> +    fprintf_unfiltered (gdb_stdlog,
> +			"x64_frame_cache:  file:%s, image_base=%s\n",
> +			objfile->name, paddress (gdbarch, image_base));
> +
> +  /* Find the entry.
> +     Note: it might be a better idea to ask directly to the kernel.  This
> +     will handle dynamically added entries (for JIT engines).  */
> +  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
> +	  (image_base + dir->VirtualAddress + mid * sizeof (d),
> +	   (char *) &d, sizeof (d)) != 0)
> +	return cache;
> +
> +      sa = extract_unsigned_integer (d.rva_BeginAddress, 4, byte_order);
> +      ea = extract_unsigned_integer (d.rva_EndAddress, 4, byte_order);
> +      if (pc < image_base + sa)
> +	hi = mid - 1;
> +      else if (pc >= image_base + ea)
> +	lo = mid + 1;
> +      else if (pc >= image_base + sa && pc < image_base + ea)
> +	{
> +	  /* Got it.  */
> +	  cache->start_address = sa;
> +	  unwind_info =
> +	    extract_unsigned_integer (d.rva_UnwindData, 4, byte_order);
> +	  break;
> +	}
> +      else
> +	break;
> +    }
> +
> +  if (unwind_debug)
> +    fprintf_unfiltered (gdb_stdlog,
> +			"x64_frame_cache:  image_base=%s, unwind_data=%s\n",
> +			paddress (gdbarch, cache->image_base),
> +			paddress (gdbarch, unwind_info));
> +
> +  if (unwind_info == 0)
> +    {
> +      /* Assume a leaf function.  */
> +      cache->prev_sp = cache->sp + 8;
> +      cache->prev_rip_addr = cache->sp;
> +    }
> +  else
> +    {
> +      if (unwind_info & 1)
> +	{
> +	  /* Unofficially documented unwind info redirection.  */
> +	  struct external_pex64_runtime_function d;
> +	  CORE_ADDR sa, ea;
> +
> +	  if (target_read_memory (image_base + (unwind_info & ~1),
> +				  (char *) &d, sizeof (d)) != 0)
> +	    return cache;
> +
> +	  cache->start_address =
> +	    extract_unsigned_integer (d.rva_BeginAddress, 4, byte_order);
> +	  unwind_info =
> +	    extract_unsigned_integer (d.rva_EndAddress, 4, byte_order);
> +	}
> +
> +      /* Decode unwind insns to compute saved addresses.  */
> +      x64_frame_decode_insns (this_frame, cache, unwind_info);
> +    }
> +  return cache;
> +}
> +
> +static struct value *
> +x64_frame_prev_register (struct frame_info *this_frame,
> +			 void **this_cache, int regnum)
> +{
> +  struct gdbarch *gdbarch = get_frame_arch (this_frame);
> +  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
> +  struct x64_frame_cache *cache = x64_frame_cache (this_frame, this_cache);
> +  struct value *val;
> +  CORE_ADDR prev;
> +
> +  if (unwind_debug)
> +    fprintf_unfiltered (gdb_stdlog, "x64_frame_prev_register %s for sp=%s\n",
> +			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 && unwind_debug)
> +    fprintf_unfiltered (gdb_stdlog, "  -> at %s\n", paddress (gdbarch, prev));
> +
> +  if (prev)
> +    return frame_unwind_got_memory (this_frame, regnum, prev);
> +  else
> +    return frame_unwind_got_register (this_frame, regnum, regnum);
> +}
> +
> +static void
> +x64_frame_this_id (struct frame_info *this_frame, void **this_cache,
> +		   struct frame_id *this_id)
> +{
> +  struct gdbarch *gdbarch = get_frame_arch (this_frame);
> +  struct x64_frame_cache *cache = x64_frame_cache (this_frame, this_cache);
> +
> +  *this_id = frame_id_build (cache->prev_sp,
> +			     cache->image_base + cache->start_address);
> +}
> +
> +/* x64 SEH unwinder.  */
> +
> +static const struct frame_unwind x64_frame_unwind =
> +{
> +  NORMAL_FRAME,
> +  default_frame_unwind_stop_reason,
> +  &x64_frame_this_id,
> +  &x64_frame_prev_register,
> +  NULL,
> +  default_frame_sniffer
> +};
>  
>  static void
>  amd64_windows_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
> @@ -174,6 +762,8 @@ amd64_windows_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
>    set_gdbarch_return_value (gdbarch, amd64_windows_return_value);
>    set_gdbarch_skip_main_prologue (gdbarch, amd64_skip_main_prologue);
>  
> +  frame_unwind_prepend_unwinder (gdbarch, &x64_frame_unwind);
> +
>    set_solib_ops (gdbarch, &solib_target_so_ops);
>  }
>  
> 
> 
> 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]