blob: 058b6ba6d6d382da2133705b48cb7c2804e48cdd [file] [log] [blame]
/*--------------------------------------------------------------------*/
/*--- Format-neutral storage of and querying of info acquired from ---*/
/*--- ELF/XCOFF stabs/dwarf1/dwarf2 debug info. ---*/
/*--- priv_storage.h ---*/
/*--------------------------------------------------------------------*/
/*
This file is part of Valgrind, a dynamic binary instrumentation
framework.
Copyright (C) 2000-2007 Julian Seward
jseward@acm.org
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 2 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, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307, USA.
The GNU General Public License is contained in the file COPYING.
*/
/*
Stabs reader greatly improved by Nick Nethercote, Apr 02.
This module was also extensively hacked on by Jeremy Fitzhardinge
and Tom Hughes.
*/
/* See comment at top of debuginfo.c for explanation of
the _svma / _avma / _image / _bias naming scheme.
*/
/* Note this is not freestanding; needs pub_core_xarray.h to be
included before it. */
#ifndef __PRIV_STORAGE_H
#define __PRIV_STORAGE_H
/* --------------------- SYMBOLS --------------------- */
/* A structure to hold an ELF/XCOFF symbol (very crudely). */
typedef
struct {
Addr addr; /* lowest address of entity */
Addr tocptr; /* ppc64-linux only: value that R2 should have */
UInt size; /* size in bytes */
UChar *name; /* name */
}
DiSym;
/* --------------------- SRCLOCS --------------------- */
/* Line count at which overflow happens, due to line numbers being
stored as shorts in `struct nlist' in a.out.h. */
#define LINENO_OVERFLOW (1 << (sizeof(short) * 8))
#define LINENO_BITS 20
#define LOC_SIZE_BITS (32 - LINENO_BITS)
#define MAX_LINENO ((1 << LINENO_BITS) - 1)
/* Unlikely to have any lines with instruction ranges > 4096 bytes */
#define MAX_LOC_SIZE ((1 << LOC_SIZE_BITS) - 1)
/* Number used to detect line number overflows; if one line is
60000-odd smaller than the previous, is was probably an overflow.
*/
#define OVERFLOW_DIFFERENCE (LINENO_OVERFLOW - 5000)
/* A structure to hold addr-to-source info for a single line. There
can be a lot of these, hence the dense packing. */
typedef
struct {
/* Word 1 */
Addr addr; /* lowest address for this line */
/* Word 2 */
UShort size:LOC_SIZE_BITS; /* # bytes; we catch overflows of this */
UInt lineno:LINENO_BITS; /* source line number, or zero */
/* Word 3 */
UChar* filename; /* source filename */
/* Word 4 */
UChar* dirname; /* source directory name */
}
DiLoc;
/* --------------------- CF INFO --------------------- */
/* A structure to summarise DWARF2/3 CFA info for the code address
range [base .. base+len-1]. In short, if you know (sp,fp,ip) at
some point and ip is in the range [base .. base+len-1], it tells
you how to calculate (sp,fp) for the caller of the current frame
and also ra, the return address of the current frame.
First off, calculate CFA, the Canonical Frame Address, thusly:
cfa = case cfa_how of
CFIC_SPREL -> sp + cfa_off
CFIC_FPREL -> fp + cfa_off
CFIR_EXPR -> expr whose index is in cfa_off
Once that is done, the previous frame's sp/fp values and this
frame's ra value can be calculated like this:
old_sp/fp/ra
= case sp/fp/ra_how of
CFIR_UNKNOWN -> we don't know, sorry
CFIR_SAME -> same as it was before (sp/fp only)
CFIR_CFAREL -> cfa + sp/fp/ra_off
CFIR_MEMCFAREL -> *( cfa + sp/fp/ra_off )
CFIR_EXPR -> expr whose index is in sp/fp/ra_off
*/
#define CFIC_SPREL ((UChar)1)
#define CFIC_FPREL ((UChar)2)
#define CFIC_EXPR ((UChar)3)
#define CFIR_UNKNOWN ((UChar)4)
#define CFIR_SAME ((UChar)5)
#define CFIR_CFAREL ((UChar)6)
#define CFIR_MEMCFAREL ((UChar)7)
#define CFIR_EXPR ((UChar)8)
typedef
struct {
Addr base;
UInt len;
UChar cfa_how; /* a CFIC_ value */
UChar ra_how; /* a CFIR_ value */
UChar sp_how; /* a CFIR_ value */
UChar fp_how; /* a CFIR_ value */
Int cfa_off;
Int ra_off;
Int sp_off;
Int fp_off;
}
DiCfSI;
typedef
enum {
Cop_Add=0x321,
Cop_Sub,
Cop_And,
Cop_Mul
}
CfiOp;
typedef
enum {
Creg_SP=0x213,
Creg_FP,
Creg_IP
}
CfiReg;
typedef
enum {
Cex_Undef=0x123,
Cex_Deref,
Cex_Const,
Cex_Binop,
Cex_CfiReg,
Cex_DwReg
}
CfiExprTag;
typedef
struct {
CfiExprTag tag;
union {
struct {
} Undef;
struct {
Int ixAddr;
} Deref;
struct {
UWord con;
} Const;
struct {
CfiOp op;
Int ixL;
Int ixR;
} Binop;
struct {
CfiReg reg;
} CfiReg;
struct {
Int reg;
} DwReg;
}
Cex;
}
CfiExpr;
extern Int ML_(CfiExpr_Undef) ( XArray* dst );
extern Int ML_(CfiExpr_Deref) ( XArray* dst, Int ixAddr );
extern Int ML_(CfiExpr_Const) ( XArray* dst, UWord con );
extern Int ML_(CfiExpr_Binop) ( XArray* dst, CfiOp op, Int ixL, Int ixR );
extern Int ML_(CfiExpr_CfiReg)( XArray* dst, CfiReg reg );
extern Int ML_(CfiExpr_DwReg) ( XArray* dst, Int reg );
extern void ML_(ppCfiExpr)( XArray* src, Int ix );
/* --------------------- SEGINFO --------------------- */
/* This is the top-level data type. It's a structure which contains
information pertaining to one mapped text segment. This type is
exported only abstractly - in pub_tool_debuginfo.h. */
#define SEGINFO_STRCHUNKSIZE (64*1024)
struct _SegInfo {
struct _SegInfo* next; /* list of SegInfos */
/* Description of the mapped segment. */
Addr text_start_avma;
UInt text_size;
UChar* filename; /* in mallocville */
UChar* memname; /* malloc'd. AIX5 only: .a member name */
OffT foffset; /* file offset for mapped text section - UNUSED */
UChar* soname;
/* An expandable array of symbols. */
DiSym* symtab;
UInt symtab_used;
UInt symtab_size;
/* An expandable array of locations. */
DiLoc* loctab;
UInt loctab_used;
UInt loctab_size;
/* An expandable array of CFI summary info records. Also includes
summary address bounds, showing the min and max address covered
by any of the records, as an aid to fast searching. And, if the
records require any expression nodes, they are stored in
cfsi_exprs. */
DiCfSI* cfsi;
UInt cfsi_used;
UInt cfsi_size;
Addr cfsi_minaddr;
Addr cfsi_maxaddr;
XArray* cfsi_exprs; /* XArray of CfSiExpr */
/* Expandable arrays of characters -- the string table. Pointers
into this are stable (the arrays are not reallocated). */
struct strchunk {
UInt strtab_used;
struct strchunk *next;
UChar strtab[SEGINFO_STRCHUNKSIZE];
} *strchunks;
/* 'text_bias' is what needs to be added to an address in the
address space of the library as stored on disk [a so-called
stated VMA] (which is not 0-based for executables or prelinked
libraries) to get an address in memory for the object loaded at
'text_start_avma'. At least for text symbols. */
OffT text_bias;
/* Bounds of data, BSS, PLT, GOT and OPD (for ppc64-linux) so that
tools can see what section an address is in. In the running
image! */
Addr plt_start_avma;
UInt plt_size;
Addr got_start_avma;
UInt got_size;
Addr opd_start_avma;
UInt opd_size;
Addr data_start_avma;
UInt data_size;
Addr bss_start_avma;
UInt bss_size;
/* Used for debugging only - indicate what stuff to dump whilst
reading stuff into the seginfo. Are computed as early in the
lifetime of the SegInfo as possible. Use these when deciding
what to spew out; do not use the global VG_(clo_blah) flags. */
Bool trace_symtab; /* symbols, our style */
Bool trace_cfi; /* dwarf frame unwind, our style */
Bool ddump_syms; /* mimic /usr/bin/readelf --syms */
Bool ddump_line; /* mimic /usr/bin/readelf --debug-dump=line */
Bool ddump_frames; /* mimic /usr/bin/readelf --debug-dump=frames */
};
/* --------------------- functions --------------------- */
/* ------ Adding ------ */
/* Add a symbol to si's symbol table. */
extern void ML_(addSym) ( struct _SegInfo* si, DiSym* sym );
/* Add a line-number record to a SegInfo. */
extern
void ML_(addLineInfo) ( struct _SegInfo* si,
UChar* filename,
UChar* dirname, /* NULL is allowable */
Addr this, Addr next, Int lineno, Int entry);
/* Add a CFI summary record. The supplied DiCfSI is copied. */
extern void ML_(addDiCfSI) ( struct _SegInfo* si, DiCfSI* cfsi );
/* Add a string to the string table of a SegInfo. If len==-1,
ML_(addStr) will itself measure the length of the string. */
extern UChar* ML_(addStr) ( struct _SegInfo* si, UChar* str, Int len );
/* Canonicalise the tables held by 'si', in preparation for use. Call
this after finishing adding entries to these tables. */
extern void ML_(canonicaliseTables) ( struct _SegInfo* si );
/* ------ Searching ------ */
/* Find a symbol-table index containing the specified pointer, or -1
if not found. Binary search. */
extern Int ML_(search_one_symtab) ( struct _SegInfo* si, Addr ptr,
Bool match_anywhere_in_fun );
/* Find a location-table index containing the specified pointer, or -1
if not found. Binary search. */
extern Int ML_(search_one_loctab) ( struct _SegInfo* si, Addr ptr );
/* Find a CFI-table index containing the specified pointer, or -1 if
not found. Binary search. */
extern Int ML_(search_one_cfitab) ( struct _SegInfo* si, Addr ptr );
/* ------ Misc ------ */
/* Show a non-fatal debug info reading error. Use vg_panic if
terminal. */
extern void ML_(symerr) ( HChar* msg );
/* Print a symbol. */
extern void ML_(ppSym) ( Int idx, DiSym* sym );
/* Print a call-frame-info summary. */
extern void ML_(ppDiCfSI) ( XArray* /* of CfiExpr */ exprs, DiCfSI* si );
#define TRACE_SYMTAB(format, args...) \
if (si->trace_symtab) { VG_(printf)(format, ## args); }
#endif /* ndef __PRIV_STORAGE_H */
/*--------------------------------------------------------------------*/
/*--- end ---*/
/*--------------------------------------------------------------------*/