|
From: <sv...@va...> - 2005-04-30 07:56:06
|
Author: sewardj
Date: 2005-04-30 08:55:58 +0100 (Sat, 30 Apr 2005)
New Revision: 3581
Modified:
trunk/coregrind/vg_dwarf.c
trunk/coregrind/vg_symtab2.c
trunk/coregrind/vg_symtab2.h
Log:
Beginnings of a DWARF CFI-based frame-unwinder. Does not yet do
anything. This is needed to get stack snapshots on amd64 code
compiled with -O, and could also be used for stack snapshots on x86
code compiled with -fomit-frame-pointer if it also has CFI info.
Modified: trunk/coregrind/vg_dwarf.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/coregrind/vg_dwarf.c 2005-04-28 10:32:02 UTC (rev 3580)
+++ trunk/coregrind/vg_dwarf.c 2005-04-30 07:55:58 UTC (rev 3581)
@@ -825,6 +825,497 @@
}
=20
=20
+/*------------------------------------------------------------*/
+/*--- Read call-frame info from an .eh_frame section ---*/
+/*------------------------------------------------------------*/
+
+/* the number of regs we are prepared to unwind */
+#define N_CFI_REGS 20
+
+/* Instructions for the automaton */
+enum dwarf_cfa_primary_ops
+ {
+ DW_CFA_use_secondary =3D 0,
+ DW_CFA_advance_loc =3D 1,
+ DW_CFA_offset =3D 2,
+ DW_CFA_restore =3D 3
+ };
+
+enum dwarf_cfa_secondary_ops
+ {
+ DW_CFA_nop =3D 0x00,
+ DW_CFA_set_loc =3D 0x01,
+ DW_CFA_advance_loc1 =3D 0x02,
+ DW_CFA_advance_loc2 =3D 0x03,
+ DW_CFA_advance_loc4 =3D 0x04,
+ DW_CFA_offset_extended =3D 0x05,
+ DW_CFA_restore_extended =3D 0x06,
+ DW_CFA_undefined =3D 0x07,
+ DW_CFA_same_value =3D 0x08,
+ DW_CFA_register =3D 0x09,
+ DW_CFA_remember_state =3D 0x0a,
+ DW_CFA_restore_state =3D 0x0b,
+ DW_CFA_def_cfa =3D 0x0c,
+ DW_CFA_def_cfa_register =3D 0x0d,
+ DW_CFA_def_cfa_offset =3D 0x0e,
+ DW_CFA_lo_user =3D 0x1c,
+ DW_CFA_GNU_args_size =3D 0x2e,
+ DW_CFA_hi_user =3D 0x3f
+ };
+
+
+typedef
+ struct {
+ enum { RR_Undef, RR_Same, RR_CFAoff, RR_Reg, RR_Arch } tag;
+
+ /* CFA offset if tag=3D=3DRR_CFAoff */
+ Int coff;
+
+ /* reg, if tag=3D=3DRR_Reg */
+ Int reg;
+ }
+ RegRule;
+
+typedef
+ struct {
+ /* Read-only fields. */
+ Int code_a_f;
+ Int data_a_f;
+ /* The rest of these fields can be modifed by
+ run_CF_instruction. */
+ /* The LOC entry */
+ Addr loc;
+ /* The CFA entry */
+ Int cfa_reg;
+ Int cfa_offset; /* in bytes */
+ /* register unwind rules */
+ RegRule reg[N_CFI_REGS];
+ }
+ UnwindContext;
+
+static void initUnwindContext ( /*OUT*/UnwindContext* ctx )
+{
+ Int i;
+ ctx->code_a_f =3D 0;
+ ctx->data_a_f =3D 0;
+ ctx->loc =3D 0;
+ ctx->cfa_reg =3D 0;
+ ctx->cfa_offset =3D 0;
+ for (i =3D 0; i < N_CFI_REGS; i++) {
+ ctx->reg[i].tag =3D RR_Undef;
+ ctx->reg[i].coff =3D 0;
+ ctx->reg[i].reg =3D 0;
+ }
+}
+
+static void ppUnwindContext ( UnwindContext* ctx )
+{
+ Int i;
+ VG_(printf)("0x%llx: ", (ULong)ctx->loc);
+ VG_(printf)("%d(r%d) ", ctx->cfa_offset, ctx->cfa_reg);
+ for (i =3D 0; i < N_CFI_REGS; i++) {
+ switch (ctx->reg[i].tag) {
+ case RR_Undef: VG_(printf)("u "); break;
+ case RR_Same: VG_(printf)("s "); break;
+ case RR_CFAoff: VG_(printf)("c%d ", ctx->reg[i].coff); break;
+ case RR_Reg: VG_(printf)("r%d ", ctx->reg[i].reg); break;
+ case RR_Arch: VG_(printf)("a "); break;
+ default: VG_(core_panic)("ppUnwindContext");
+ }
+ }
+ VG_(printf)("\n");
+}
+
+static inline Bool host_is_little_endian ( void )
+{
+ UInt x =3D 0x76543210;
+ UChar* p =3D (UChar*)(&x);
+ return toBool(*p =3D=3D 0x10);
+}
+
+
+static UShort read_UShort ( UChar* data )
+{
+ vg_assert(host_is_little_endian());
+ UInt r =3D 0;
+ r =3D data[0]=20
+ | ( ((UInt)data[1]) << 8 );
+ return r;
+}
+
+static UInt read_UInt ( UChar* data )
+{
+ vg_assert(host_is_little_endian());
+ UInt r =3D 0;
+ r =3D data[0]=20
+ | ( ((UInt)data[1]) << 8 )=20
+ | ( ((UInt)data[2]) << 16 )=20
+ | ( ((UInt)data[3]) << 24 );
+ return r;
+}
+
+static Addr read_Addr ( UChar* data )
+{
+ if (sizeof(Addr) =3D=3D 4)
+ return read_UInt(data);
+ vg_assert(0);
+}
+
+static UChar read_UChar ( UChar* data )
+{
+ return data[0];
+}
+
+
+/* Run a CFI instruction, and also return its length.
+ Returns 0 if the instruction could not be executed.=20
+*/
+static Int run_CF_instruction ( /*MOD*/UnwindContext* ctx,=20
+ UChar* instr )
+{
+ Int off, reg, nleb;
+ UInt delta;
+ Int i =3D 0;
+ UChar hi2 =3D (instr[i] >> 6) & 3;
+ UChar lo6 =3D instr[i] & 0x3F;
+ i++;
+
+ if (hi2 =3D=3D DW_CFA_advance_loc) {
+ delta =3D (UInt)lo6;
+ ctx->loc +=3D delta;
+ return i;
+ }
+
+ if (hi2 =3D=3D DW_CFA_offset) {
+ /* Set rule for reg 'lo6' to CFAoffset(off * data_af) */
+ off =3D read_leb128( &instr[i], &nleb, 0 );
+ i +=3D nleb;
+ reg =3D (Int)lo6;
+ if (reg < 0 || reg >=3D N_CFI_REGS)=20
+ return 0; /* fail */
+ ctx->reg[reg].tag =3D RR_CFAoff;
+ ctx->reg[reg].coff =3D off * ctx->data_a_f;
+ return i;
+ }
+
+ if (hi2 =3D=3D DW_CFA_restore) {
+ vg_assert(0);
+ VG_(printf)("DW_CFA_restore(%d)\n", (Int)lo6);
+ return i;
+ }
+
+ vg_assert(hi2 =3D=3D DW_CFA_use_secondary);
+
+ switch (lo6) {
+ case DW_CFA_nop:=20
+ break;
+ case DW_CFA_advance_loc1:
+ vg_assert(0);
+ delta =3D (UInt)read_UChar(&instr[i]); i+=3D sizeof(UChar);
+ VG_(printf)("DW_CFA_advance_loc1(%d)\n", delta);=20
+ break;
+
+ case DW_CFA_def_cfa:
+ reg =3D read_leb128( &instr[i], &nleb, 0 );
+ i +=3D nleb;
+ off =3D read_leb128( &instr[i], &nleb, 0 );
+ i +=3D nleb;
+ if (reg < 0 || reg >=3D N_CFI_REGS)=20
+ return 0; /* fail */
+ ctx->cfa_reg =3D reg;
+ ctx->cfa_offset =3D off;
+ break;
+
+ case DW_CFA_def_cfa_register: {
+ reg =3D read_leb128( &instr[i], &nleb, 0);
+ i +=3D nleb;
+ if (reg < 0 || reg >=3D N_CFI_REGS)=20
+ return 0; /* fail */
+ ctx->cfa_reg =3D reg;
+ break;
+ }
+ case DW_CFA_def_cfa_offset: {
+ off =3D read_leb128( &instr[i], &nleb, 0);
+ i +=3D nleb;
+ ctx->cfa_offset =3D off;
+ break;
+ }
+ case DW_CFA_GNU_args_size: {
+ /* No idea what is supposed to happen. gdb-6.3 simply
+ ignores these. */
+ off =3D read_leb128( &instr[i], &nleb, 0 );
+ i +=3D nleb;
+ break;
+ }
+ default:=20
+ vg_assert(0);
+ VG_(printf)("0:%d\n", (Int)lo6);=20
+ break;
+ }
+
+ return i; =20
+}
+
+
+/* Show a CFI instruction, and also return its length. */
+static Int show_CF_instruction ( UChar* instr )
+{
+ UInt delta;
+ Int off, reg, nleb;
+ Int i =3D 0;
+ UChar hi2 =3D (instr[i] >> 6) & 3;
+ UChar lo6 =3D instr[i] & 0x3F;
+ i++;
+
+ if (hi2 =3D=3D DW_CFA_advance_loc) {
+ VG_(printf)("DW_CFA_advance_loc(%d)\n", (Int)lo6);
+ return i;
+ }
+
+ if (hi2 =3D=3D DW_CFA_offset) {
+ off =3D read_leb128( &instr[i], &nleb, 0 );
+ i +=3D nleb;
+ VG_(printf)("DW_CFA_offset(r%d + %d x data_af)\n", (Int)lo6, off);
+ return i;
+ }
+
+ if (hi2 =3D=3D DW_CFA_restore) {
+ VG_(printf)("DW_CFA_restore(%d)\n", (Int)lo6);
+ return i;
+ }
+
+ vg_assert(hi2 =3D=3D DW_CFA_use_secondary);
+
+ switch (lo6) {
+
+ case DW_CFA_nop:=20
+ VG_(printf)("DW_CFA_nop\n");=20
+ break;
+
+ case DW_CFA_advance_loc1:
+ delta =3D (UInt)read_UChar(&instr[i]); i+=3D sizeof(UChar);
+ VG_(printf)("DW_CFA_advance_loc1(%d)\n", delta);=20
+ break;
+
+ case DW_CFA_def_cfa:
+ reg =3D read_leb128( &instr[i], &nleb, 0 );
+ i +=3D nleb;
+ off =3D read_leb128( &instr[i], &nleb, 0 );
+ i +=3D nleb;
+ VG_(printf)("DW_CFA_def_cfa(r%d, off %d)\n", reg, off);=20
+ break;
+
+ case DW_CFA_def_cfa_register:
+ reg =3D read_leb128( &instr[i], &nleb, 0);
+ i +=3D nleb;
+ VG_(printf)("DW_CFA_def_cfa_register(r%d)\n", reg);=20
+ break;
+
+ case DW_CFA_def_cfa_offset:=20
+ off =3D read_leb128( &instr[i], &nleb, 0);
+ i +=3D nleb;
+ VG_(printf)("DW_CFA_def_cfa_offset(%d)\n", off);=20
+ break;
+
+ case DW_CFA_GNU_args_size:
+ off =3D read_leb128( &instr[i], &nleb, 0 );
+ i +=3D nleb;
+ VG_(printf)("DW_CFA_GNU_args_size(%d)\n", off );=20
+ break;
+
+ default:=20
+ VG_(printf)("0:%d\n", (Int)lo6);=20
+ break;
+ }
+
+ return i;
+}
+
+
+static void show_CF_instructions ( UChar* instrs, Int ilen )
+{
+ Int i =3D 0;
+ while (True) {
+ if (i >=3D ilen) break;
+ i +=3D show_CF_instruction( &instrs[i] );
+ }
+}
+
+/* Run the CF instructions in instrs[0 .. ilen-1], until the end is
+ reached, or until there is a failure. Return True iff success.=20
+*/
+static=20
+Bool run_CF_instructions ( UnwindContext* ctx, UChar* instrs, Int ilen )
+{
+ Int j, i =3D 0;
+ ppUnwindContext(ctx);
+ while (True) {
+ if (i >=3D ilen) break;
+ if (0) (void)show_CF_instruction( &instrs[i] );
+ j =3D run_CF_instruction( ctx, &instrs[i] );
+ if (j =3D=3D 0)
+ return False; /* execution failed */
+ i +=3D j;
+ ppUnwindContext(ctx);
+ }
+ return True;
+}
+
+
+void VG_(read_callframe_info_dwarf2)=20
+ ( /*OUT*/SegInfo* si, UChar* ehframe, Int ehframe_sz )
+{
+ UnwindContext ctx;
+ Int nbytes;
+ HChar* how =3D NULL;
+ Int cie_codeaf =3D 0;
+ Int cie_dataaf =3D 0;
+ Bool ok;
+
+ UChar* current_cie =3D NULL;
+
+ if (ehframe_sz !=3D 240) return;
+ VG_(printf)("\n\n\neh_frame %p %d\n", ehframe, ehframe_sz);
+
+ UChar* data =3D ehframe;
+
+ UChar* cie_instrs =3D NULL;
+ Int cie_ilen =3D 0;
+
+ /* Loop over CIEs/FDEs */
+
+ while (True) {
+
+ /* Are we done? */
+ if (data =3D=3D ehframe + ehframe_sz)
+ return;
+
+ /* Overshot the end? Means something is wrong */
+ if (data > ehframe + ehframe_sz) {
+ how =3D "overran the end of .eh_frame";
+ goto bad;
+ }
+
+ /* Ok, we must be looking at the start of a new CIE or FDE.
+ Figure out which it is. */
+
+ UChar* ciefde_start =3D data;
+ VG_(printf)("\ncie/fde.start =3D %p\n", ciefde_start);
+
+ UInt ciefde_len =3D read_UInt(data); data +=3D sizeof(UInt);
+ VG_(printf)("cie/fde.length =3D %d\n", ciefde_len);
+
+ /* Apparently, if the .length field is zero, we are at the end
+ of the sequence. ?? Neither the DWARF2 spec not the AMD64
+ ABI spec say this, though. */
+ if (ciefde_len =3D=3D 0) {
+ if (data =3D=3D ehframe + ehframe_sz)
+ return;
+ how =3D "zero-sized CIE/FDE but not at section end\n";
+ goto bad;
+ }
+
+ UInt cie_pointer =3D read_UInt(data); data +=3D sizeof(UInt);
+ VG_(printf)("cie.pointer =3D %d\n", cie_pointer);
+
+ /* If cie_pointer is zero, we've got a CIE; else it's an FDE. */
+ if (cie_pointer =3D=3D 0) {
+
+ /* Remember the start proper of the current CIE */
+ current_cie =3D ciefde_start + sizeof(UInt);
+
+ /* --------- CIE --------- */
+ UChar cie_version =3D read_UChar(data); data +=3D sizeof(UChar)=
;
+ VG_(printf)("cie.version =3D %d\n", (Int)cie_version);
+
+ UChar* cie_augmentation =3D data;
+ data +=3D 1 + VG_(strlen)(cie_augmentation);
+ VG_(printf)("cie.augment =3D \"%s\"\n", cie_augmentation);
+
+ if (0 !=3D VG_(strcmp)(cie_augmentation, "")) {
+ how =3D "non-NULL cie.augmentation";
+ goto bad;
+ }
+
+ cie_codeaf =3D read_leb128( data, &nbytes, 0);
+ data +=3D nbytes;
+ VG_(printf)("cie.code_af =3D %d\n", cie_codeaf);
+
+ cie_dataaf =3D read_leb128( data, &nbytes, 1);
+ data +=3D nbytes;
+ VG_(printf)("cie.data_af =3D %d\n", cie_dataaf);
+
+ UChar cie_rareg =3D read_UChar(data); data +=3D sizeof(UChar);
+ VG_(printf)("cie.ra_reg =3D %d\n", (Int)cie_rareg);
+
+ cie_instrs =3D data;
+ cie_ilen =3D ciefde_start + ciefde_len + sizeof(UInt) - data;
+ VG_(printf)("cie.instrs =3D %p\n", (Int)cie_instrs);
+ VG_(printf)("cie.ilen =3D %d\n", (Int)cie_ilen);
+
+ if (cie_ilen < 0 || cie_ilen > ehframe_sz) {
+ how =3D "implausible # cie initial insns";
+ goto bad;
+ }
+
+ data +=3D cie_ilen;
+
+ show_CF_instructions(cie_instrs, cie_ilen);
+
+ } else {
+
+ /* --------- FDE --------- */
+
+ /* Ensure that (1) we have a valid CIE, and (2) that=20
+ it is indeed the CIE referred to by this FDE. */
+ if (current_cie =3D=3D NULL) {
+ how =3D "FDE with no preceding CIE";
+ goto bad;
+ }
+ if (cie_pointer !=3D data - current_cie) {
+ how =3D "FDE does not refer to preceding CIE";
+ goto bad;
+ }
+
+ Addr fde_initloc =3D read_Addr(data); data +=3D sizeof(Addr);
+ VG_(printf)("fde.initloc =3D %p\n", (void*)fde_initloc);
+
+ UWord fde_arange =3D read_Addr(data); data +=3D sizeof(Addr);
+ VG_(printf)("fde.arangec =3D %p\n", (void*)fde_arange);
+
+ UChar* fde_instrs =3D data;
+ Int fde_ilen =3D ciefde_start + ciefde_len + sizeof(UInt) =
- data;
+ VG_(printf)("fde.instrs =3D %p\n", (Int)fde_instrs);
+ VG_(printf)("fde.ilen =3D %d\n", (Int)fde_ilen);
+
+ if (fde_ilen < 0 || fde_ilen > ehframe_sz) {
+ how =3D "implausible # fde initial insns";
+ goto bad;
+ }
+
+ data +=3D fde_ilen;
+
+ initUnwindContext(&ctx);
+ ctx.code_a_f =3D cie_codeaf;
+ ctx.data_a_f =3D cie_dataaf;
+ ok =3D run_CF_instructions(&ctx, cie_instrs, cie_ilen);
+ if (ok)
+ ok =3D run_CF_instructions(&ctx, fde_instrs, fde_ilen);
+ }
+ }
+
+ /* Read a CIE and remember important bits */
+
+
+
+ return;
+
+ bad:
+ VG_(message)(Vg_UserMsg, "Warning: %s in DWARF2 CIE reading", how);
+ return;
+}
+
+
/*--------------------------------------------------------------------*/
/*--- end vg_dwarf.c ---*/
/*--------------------------------------------------------------------*/
Modified: trunk/coregrind/vg_symtab2.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/coregrind/vg_symtab2.c 2005-04-28 10:32:02 UTC (rev 3580)
+++ trunk/coregrind/vg_symtab2.c 2005-04-30 07:55:58 UTC (rev 3581)
@@ -96,6 +96,7 @@
if (si->symtab) VG_(arena_free)(VG_AR_SYMTAB, si->symtab);
if (si->loctab) VG_(arena_free)(VG_AR_SYMTAB, si->loctab);
if (si->scopetab) VG_(arena_free)(VG_AR_SYMTAB, si->scopetab);
+ if (si->cfisi) VG_(arena_free)(VG_AR_SYMTAB, si->cfisi);
=20
for(chunk =3D si->strchunks; chunk !=3D NULL; chunk =3D next) {
next =3D chunk->next;
@@ -1455,6 +1456,7 @@
UChar* debug_line =3D NULL; /* .debug_line (dwarf2) */
UChar* dwarf1d =3D NULL; /* .debug (dwarf1) */
UChar* dwarf1l =3D NULL; /* .line (dwarf1) */
+ UChar* ehframe =3D NULL; /* .eh_frame (dwarf2) */
=20
/* Section sizes, in bytes */
UInt o_strtab_sz =3D 0;
@@ -1467,6 +1469,7 @@
UInt debug_line_sz =3D 0;
UInt dwarf1d_sz =3D 0;
UInt dwarf1l_sz =3D 0;
+ UInt ehframe_sz =3D 0;
=20
Bool has_debuginfo =3D False;
=20
@@ -1503,6 +1506,7 @@
else FIND(".debug_line", debug_line, debug_line_sz, 0, UCha=
r*)
else FIND(".debug", dwarf1d, dwarf1d_sz, 0, UCha=
r*)
else FIND(".line", dwarf1l, dwarf1l_sz, 0, UCha=
r*)
+ else FIND(".eh_frame", ehframe, ehframe_sz, 0, UCha=
r*)
=20
else FIND(".got", si->got_start, si->got_size, 1, Addr=
)
else FIND(".plt", si->plt_start, si->plt_size, 1, Addr=
)
@@ -1575,6 +1579,11 @@
}
}
=20
+ /* Read .eh_frame (call-frame-info) if any */
+ if (ehframe && ehframe_sz > 4) {
+ VG_(read_callframe_info_dwarf2) ( si, ehframe, ehframe_sz );
+ }
+
/* Read the stabs and/or dwarf2 debug information, if any. */
if (stab !=3D NULL && stabstr !=3D NULL) {
has_debuginfo =3D True;
@@ -1591,9 +1600,10 @@
dwarf1l, dwarf1l_sz );
}=20
if (!has_debuginfo) {
- VG_(symerr)(" object doesn't have any debug info");
+ VG_(symerr)(" object doesn't have any line number info");
goto out;
}
+
}
res =3D True;
=20
@@ -1646,6 +1656,8 @@
si->strchunks =3D NULL;
si->scopetab =3D NULL;
si->scopetab_size =3D si->scopetab_used =3D 0;
+ si->cfisi =3D NULL;
+ si->cfisi_size =3D si->cfisi_used =3D 0;
=20
si->seg =3D seg;
=20
Modified: trunk/coregrind/vg_symtab2.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/coregrind/vg_symtab2.h 2005-04-28 10:32:02 UTC (rev 3580)
+++ trunk/coregrind/vg_symtab2.h 2005-04-30 07:55:58 UTC (rev 3581)
@@ -117,6 +117,21 @@
=20
#define STRCHUNKSIZE (64*1024)
=20
+
+/* A structure to summarise CFI summary info. It defines an address
+ range, and for that address range, gives info on how the
+ procedure's return address is to be derived from the current stack
+ pointer value in that range. For example, if .raoffset is 16, then
+ the return address is found in memory at (SP+16). */
+typedef
+ struct {
+ Addr base;
+ UInt len;
+ Int raoffset;
+ }
+ CfiSI;
+
+
/* A structure which contains information pertaining to one mapped
text segment. (typedef in tool.h) */
struct _SegInfo {
@@ -144,6 +159,10 @@
ScopeRange *scopetab;
UInt scopetab_used;
UInt scopetab_size;
+ /* An expandable array of CFI summary info records. */
+ CfiSI* cfisi;
+ UInt cfisi_used;
+ UInt cfisi_size;
=20
/* Expandable arrays of characters -- the string table.
Pointers into this are stable (the arrays are not reallocated)
@@ -201,7 +220,13 @@
UChar* dwarf1d, Int dwarf1d_sz,=20
UChar* dwarf1l, Int dwarf1l_sz );
=20
+/* --------------------
+ CFI reader
+ -------------------- */
+void VG_(read_callframe_info_dwarf2)=20
+ ( /*OUT*/SegInfo* si, UChar* ehframe, Int ehframe_sz );
=20
+
#endif /* _VG_SYMTYPE_H */
=20
/*--------------------------------------------------------------------*/
|