mirror of
https://github.com/Zenithsiz/ftmemsim-valgrind.git
synced 2026-02-03 18:13:01 +00:00
1484 lines
38 KiB
Plaintext
1484 lines
38 KiB
Plaintext
|
|
/*--------------------------------------------------------------------*/
|
|
/*--- Extract type info from debug info. symtypes.h ---*/
|
|
/*--------------------------------------------------------------------*/
|
|
|
|
/*
|
|
This file is part of Valgrind, a dynamic binary instrumentation
|
|
framework.
|
|
|
|
Copyright (C) 2000-2005 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.
|
|
*/
|
|
|
|
#include "pub_core_basics.h"
|
|
#include "pub_core_debuginfo.h"
|
|
#include "pub_core_debuglog.h" // For VG_(debugLog_vprintf)
|
|
#include "pub_core_libcbase.h"
|
|
#include "pub_core_libcassert.h"
|
|
#include "pub_core_libcprint.h"
|
|
#include "pub_core_libcsignal.h"
|
|
#include "pub_core_machine.h"
|
|
#include "pub_core_mallocfree.h"
|
|
|
|
#include "priv_symtypes.h"
|
|
|
|
typedef enum {
|
|
TyUnknown, /* unknown type */
|
|
TyUnresolved, /* unresolved type */
|
|
TyError, /* error type */
|
|
|
|
TyVoid, /* void */
|
|
|
|
TyInt, /* integer */
|
|
TyBool, /* boolean */
|
|
TyChar, /* character */
|
|
TyFloat, /* float */
|
|
|
|
TyRange, /* type subrange */
|
|
|
|
TyEnum, /* enum */
|
|
|
|
TyPointer, /* pointer */
|
|
TyArray, /* array */
|
|
TyStruct, /* structure/class */
|
|
TyUnion, /* union */
|
|
|
|
TyTypedef /* typedef */
|
|
} TyKind;
|
|
|
|
static const Char *ppkind(TyKind k)
|
|
{
|
|
switch(k) {
|
|
#define S(x) case x: return #x
|
|
S(TyUnknown);
|
|
S(TyUnresolved);
|
|
S(TyError);
|
|
S(TyVoid);
|
|
S(TyInt);
|
|
S(TyBool);
|
|
S(TyChar);
|
|
S(TyRange);
|
|
S(TyFloat);
|
|
S(TyEnum);
|
|
S(TyPointer);
|
|
S(TyArray);
|
|
S(TyStruct);
|
|
S(TyUnion);
|
|
S(TyTypedef);
|
|
#undef S
|
|
default:
|
|
return "Ty???";
|
|
}
|
|
}
|
|
|
|
/* struct/union field */
|
|
typedef struct _StField {
|
|
UInt offset; /* offset into structure (0 for union) (in bits) */
|
|
UInt size; /* size (in bits) */
|
|
SymType *type; /* type of element */
|
|
Char *name; /* name of element */
|
|
} StField;
|
|
|
|
/* enum tag */
|
|
typedef struct _EnTag {
|
|
const Char *name; /* name */
|
|
UInt val; /* value */
|
|
} EnTag;
|
|
|
|
struct _SymType {
|
|
TyKind kind; /* type descriminator */
|
|
UInt size; /* sizeof(type) */
|
|
Char *name; /* useful name */
|
|
|
|
union {
|
|
/* TyInt,TyBool,TyChar */
|
|
struct {
|
|
Bool issigned; /* signed or not */
|
|
} t_scalar;
|
|
|
|
/* TyFloat */
|
|
struct {
|
|
Bool isdouble; /* is double prec */
|
|
} t_float;
|
|
|
|
/* TyRange */
|
|
struct {
|
|
Int min;
|
|
Int max;
|
|
SymType *type;
|
|
} t_range;
|
|
|
|
/* TyPointer */
|
|
struct {
|
|
SymType *type; /* *type */
|
|
} t_pointer;
|
|
|
|
/* TyArray */
|
|
struct {
|
|
SymType *idxtype;
|
|
SymType *type;
|
|
} t_array;
|
|
|
|
/* TyEnum */
|
|
struct {
|
|
UInt ntag; /* number of tags */
|
|
EnTag *tags; /* tags */
|
|
} t_enum;
|
|
|
|
/* TyStruct, TyUnion */
|
|
struct {
|
|
UInt nfield; /* number of fields */
|
|
UInt nfieldalloc; /* number of fields allocated */
|
|
StField *fields; /* fields */
|
|
} t_struct;
|
|
|
|
/* TyTypedef */
|
|
struct {
|
|
SymType *type; /* type */
|
|
} t_typedef;
|
|
|
|
/* TyUnresolved - reference to unresolved type */
|
|
struct {
|
|
/* some kind of symtab reference */
|
|
SymResolver *resolver; /* symtab reader's resolver */
|
|
void *data; /* data for resolver */
|
|
} t_unresolved;
|
|
} u;
|
|
};
|
|
|
|
|
|
Bool ML_(st_isstruct)(SymType *ty)
|
|
{
|
|
return ty->kind == TyStruct;
|
|
}
|
|
|
|
Bool ML_(st_isunion)(SymType *ty)
|
|
{
|
|
return ty->kind == TyUnion;
|
|
}
|
|
|
|
Bool ML_(st_isenum)(SymType *ty)
|
|
{
|
|
return ty->kind == TyEnum;
|
|
}
|
|
|
|
static inline SymType *alloc(SymType *st)
|
|
{
|
|
if (st == NULL) {
|
|
st = VG_(arena_malloc)(VG_AR_SYMTAB, sizeof(*st));
|
|
st->kind = TyUnknown;
|
|
st->name = NULL;
|
|
}
|
|
|
|
return st;
|
|
}
|
|
|
|
static void resolve(SymType *st)
|
|
{
|
|
if (st->kind != TyUnresolved)
|
|
return;
|
|
|
|
(*st->u.t_unresolved.resolver)(st, st->u.t_unresolved.data);
|
|
|
|
if (st->kind == TyUnresolved)
|
|
st->kind = TyError;
|
|
}
|
|
|
|
SymType *ML_(st_mkunresolved)(SymType *st, SymResolver *resolver, void *data)
|
|
{
|
|
st = alloc(st);
|
|
|
|
vg_assert(st->kind == TyUnresolved || st->kind == TyUnknown);
|
|
|
|
st->kind = TyUnresolved;
|
|
st->size = 0;
|
|
st->u.t_unresolved.resolver = resolver;
|
|
st->u.t_unresolved.data = data;
|
|
|
|
return st;
|
|
}
|
|
|
|
void ML_(st_unresolved_setdata)(SymType *st, SymResolver *resolver, void *data)
|
|
{
|
|
if (st->kind != TyUnresolved)
|
|
return;
|
|
|
|
st->u.t_unresolved.resolver = resolver;
|
|
st->u.t_unresolved.data = data;
|
|
}
|
|
|
|
Bool ML_(st_isresolved)(SymType *st)
|
|
{
|
|
return st->kind != TyUnresolved;
|
|
}
|
|
|
|
void ML_(st_setname)(SymType *st, Char *name)
|
|
{
|
|
if (st->name != NULL)
|
|
st->name = name;
|
|
}
|
|
|
|
SymType *ML_(st_mkvoid)(SymType *st)
|
|
{
|
|
st = alloc(st);
|
|
|
|
vg_assert(st->kind == TyUnresolved || st->kind == TyUnknown);
|
|
|
|
st->kind = TyVoid;
|
|
st->size = 1; /* for address calculations */
|
|
st->name = "void";
|
|
return st;
|
|
}
|
|
|
|
SymType *ML_(st_mkint)(SymType *st, UInt size, Bool isSigned)
|
|
{
|
|
st = alloc(st);
|
|
|
|
vg_assert(st->kind == TyUnresolved || st->kind == TyUnknown);
|
|
|
|
st->kind = TyInt;
|
|
st->size = size;
|
|
st->u.t_scalar.issigned = isSigned;
|
|
|
|
return st;
|
|
}
|
|
|
|
SymType *ML_(st_mkfloat)(SymType *st, UInt size)
|
|
{
|
|
st = alloc(st);
|
|
|
|
vg_assert(st->kind == TyUnresolved || st->kind == TyUnknown);
|
|
|
|
st->kind = TyFloat;
|
|
st->size = size;
|
|
st->u.t_scalar.issigned = True;
|
|
|
|
return st;
|
|
}
|
|
|
|
SymType *ML_(st_mkbool)(SymType *st, UInt size)
|
|
{
|
|
st = alloc(st);
|
|
|
|
vg_assert(st->kind == TyUnresolved || st->kind == TyUnknown);
|
|
|
|
st->kind = TyBool;
|
|
st->size = size;
|
|
|
|
return st;
|
|
}
|
|
|
|
|
|
SymType *ML_(st_mkpointer)(SymType *st, SymType *ptr)
|
|
{
|
|
st = alloc(st);
|
|
|
|
vg_assert(st->kind == TyUnresolved || st->kind == TyUnknown);
|
|
|
|
st->kind = TyPointer;
|
|
st->size = sizeof(void *);
|
|
st->u.t_pointer.type = ptr;
|
|
|
|
return st;
|
|
}
|
|
|
|
SymType *ML_(st_mkrange)(SymType *st, SymType *ty, Int min, Int max)
|
|
{
|
|
st = alloc(st);
|
|
|
|
vg_assert(st->kind == TyUnresolved || st->kind == TyUnknown);
|
|
|
|
st->kind = TyRange;
|
|
st->size = 0; /* ? */
|
|
st->u.t_range.type = ty;
|
|
st->u.t_range.min = min;
|
|
st->u.t_range.max = max;
|
|
|
|
return st;
|
|
}
|
|
|
|
SymType *ML_(st_mkstruct)(SymType *st, UInt size, UInt nfields)
|
|
{
|
|
st = alloc(st);
|
|
|
|
vg_assert(st->kind == TyUnresolved || st->kind == TyUnknown || st->kind == TyStruct);
|
|
|
|
vg_assert(st->kind != TyStruct || st->u.t_struct.nfield == 0);
|
|
|
|
st->kind = TyStruct;
|
|
st->size = size;
|
|
st->u.t_struct.nfield = 0;
|
|
st->u.t_struct.nfieldalloc = nfields;
|
|
if (nfields != 0)
|
|
st->u.t_struct.fields = VG_(arena_malloc)(VG_AR_SYMTAB, sizeof(StField) * nfields);
|
|
else
|
|
st->u.t_struct.fields = NULL;
|
|
|
|
return st;
|
|
}
|
|
|
|
SymType *ML_(st_mkunion)(SymType *st, UInt size, UInt nfields)
|
|
{
|
|
st = alloc(st);
|
|
|
|
vg_assert(st->kind == TyUnresolved || st->kind == TyUnknown || st->kind == TyUnion);
|
|
|
|
vg_assert(st->kind != TyUnion || st->u.t_struct.nfield == 0);
|
|
|
|
st->kind = TyUnion;
|
|
st->size = size;
|
|
st->u.t_struct.nfield = 0;
|
|
st->u.t_struct.nfieldalloc = nfields;
|
|
if (nfields != 0)
|
|
st->u.t_struct.fields = VG_(arena_malloc)(VG_AR_SYMTAB, sizeof(StField) * nfields);
|
|
else
|
|
st->u.t_struct.fields = NULL;
|
|
|
|
return st;
|
|
}
|
|
|
|
void ML_(st_addfield)(SymType *st, Char *name, SymType *type, UInt off, UInt size)
|
|
{
|
|
StField *f;
|
|
|
|
vg_assert(st->kind == TyStruct || st->kind == TyUnion);
|
|
|
|
if (st->u.t_struct.nfieldalloc == st->u.t_struct.nfield) {
|
|
StField *n = VG_(arena_malloc)(VG_AR_SYMTAB,
|
|
sizeof(StField) * (st->u.t_struct.nfieldalloc + 2));
|
|
VG_(memcpy)(n, st->u.t_struct.fields, sizeof(*n) * st->u.t_struct.nfield);
|
|
if (st->u.t_struct.fields != NULL)
|
|
VG_(arena_free)(VG_AR_SYMTAB, st->u.t_struct.fields);
|
|
st->u.t_struct.nfieldalloc++;
|
|
st->u.t_struct.fields = n;
|
|
}
|
|
|
|
f = &st->u.t_struct.fields[st->u.t_struct.nfield++];
|
|
f->name = name;
|
|
f->type = type;
|
|
f->offset = off;
|
|
f->size = size;
|
|
}
|
|
|
|
|
|
SymType *ML_(st_mkenum)(SymType *st, UInt ntags)
|
|
{
|
|
st = alloc(st);
|
|
|
|
vg_assert(st->kind == TyUnresolved || st->kind == TyUnknown || st->kind == TyEnum);
|
|
|
|
st->kind = TyEnum;
|
|
st->u.t_enum.ntag = 0;
|
|
st->u.t_enum.tags = NULL;
|
|
|
|
return st;
|
|
}
|
|
|
|
SymType *ML_(st_mkarray)(SymType *st, SymType *idxtype, SymType *type)
|
|
{
|
|
st = alloc(st);
|
|
|
|
vg_assert(st->kind == TyUnresolved || st->kind == TyUnknown);
|
|
|
|
st->kind = TyArray;
|
|
st->u.t_array.type = type;
|
|
st->u.t_array.idxtype = idxtype;
|
|
|
|
return st;
|
|
}
|
|
|
|
SymType *ML_(st_mktypedef)(SymType *st, Char *name, SymType *type)
|
|
{
|
|
st = alloc(st);
|
|
|
|
vg_assert(st != type);
|
|
vg_assert(st->kind == TyUnresolved || st->kind == TyUnknown ||
|
|
st->kind == TyStruct || st->kind == TyUnion ||
|
|
st->kind == TyTypedef);
|
|
|
|
st->kind = TyTypedef;
|
|
st->name = name;
|
|
st->u.t_typedef.type = type;
|
|
|
|
return st;
|
|
}
|
|
|
|
|
|
SymType *ML_(st_basetype)(SymType *type, Bool do_resolve)
|
|
{
|
|
while (type->kind == TyTypedef || (do_resolve && type->kind == TyUnresolved)) {
|
|
if (do_resolve)
|
|
resolve(type);
|
|
|
|
if (type->kind == TyTypedef)
|
|
type = type->u.t_typedef.type;
|
|
}
|
|
|
|
return type;
|
|
}
|
|
|
|
UInt ML_(st_sizeof)(SymType *ty)
|
|
{
|
|
return ty->size;
|
|
}
|
|
|
|
#ifndef TEST
|
|
/*
|
|
Hash of visited addresses, so we don't get stuck in loops. It isn't
|
|
simply enough to keep track of addresses, since we need to interpret
|
|
the memory according to the type. If a given location has multiple
|
|
pointers with different types (for example, void * and struct foo *),
|
|
then we need to look at it under each type.
|
|
*/
|
|
struct visited {
|
|
Addr a;
|
|
SymType *ty;
|
|
struct visited *next;
|
|
};
|
|
|
|
#define VISIT_HASHSZ 1021
|
|
|
|
static struct visited *visit_hash[VISIT_HASHSZ];
|
|
|
|
static inline Bool test_visited(Addr a, SymType *type)
|
|
{
|
|
struct visited *v;
|
|
UInt b = (UInt)a % VISIT_HASHSZ;
|
|
Bool ret = False;
|
|
|
|
for(v = visit_hash[b]; v != NULL; v = v->next) {
|
|
if (v->a == a && v->ty == type) {
|
|
ret = True;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static Bool has_visited(Addr a, SymType *type)
|
|
{
|
|
static const Bool debug = False;
|
|
Bool ret;
|
|
|
|
ret = test_visited(a, type);
|
|
|
|
if (!ret) {
|
|
UInt b = (UInt)a % VISIT_HASHSZ;
|
|
struct visited * v = VG_(arena_malloc)(VG_AR_SYMTAB, sizeof(*v));
|
|
|
|
v->a = a;
|
|
v->ty = type;
|
|
v->next = visit_hash[b];
|
|
visit_hash[b] = v;
|
|
}
|
|
|
|
if (debug)
|
|
VG_(printf)("has_visited(a=%p, ty=%p) -> %d\n", a, type, ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void clear_visited(void)
|
|
{
|
|
UInt i;
|
|
|
|
for(i = 0; i < VISIT_HASHSZ; i++) {
|
|
struct visited *v, *n;
|
|
for(v = visit_hash[i]; v != NULL; v = n) {
|
|
n = v->next;
|
|
VG_(arena_free)(VG_AR_SYMTAB, v);
|
|
}
|
|
visit_hash[i] = NULL;
|
|
}
|
|
}
|
|
|
|
static
|
|
void bprintf(void (*send)(HChar, void*), void *send_arg, const Char *fmt, ...)
|
|
{
|
|
va_list vargs;
|
|
|
|
va_start(vargs, fmt);
|
|
VG_(debugLog_vprintf)(send, send_arg, fmt, vargs);
|
|
va_end(vargs);
|
|
}
|
|
|
|
#define SHADOWCHUNK 0 /* no longer have a core allocator */
|
|
|
|
#if SHADOWCHUNK
|
|
static ShadowChunk *findchunk(Addr a)
|
|
{
|
|
Bool find(ShadowChunk *sc) {
|
|
return a >= sc->data && a < (sc->data+sc->size);
|
|
}
|
|
return VG_(any_matching_mallocd_ShadowChunks)(find);
|
|
}
|
|
#endif
|
|
|
|
static struct vki_sigaction sigbus_saved;
|
|
static struct vki_sigaction sigsegv_saved;
|
|
static vki_sigset_t blockmask_saved;
|
|
static jmp_buf valid_addr_jmpbuf;
|
|
|
|
static void valid_addr_handler(int sig)
|
|
{
|
|
//VG_(printf)("OUCH! %d\n", sig);
|
|
__builtin_longjmp(valid_addr_jmpbuf, 1);
|
|
}
|
|
|
|
/* catch badness signals because we're going to be
|
|
playing around in untrusted memory */
|
|
static void setup_signals(void)
|
|
{
|
|
Int res;
|
|
struct vki_sigaction sigbus_new;
|
|
struct vki_sigaction sigsegv_new;
|
|
vki_sigset_t unblockmask_new;
|
|
|
|
/* Temporarily install a new sigsegv and sigbus handler, and make
|
|
sure SIGBUS, SIGSEGV and SIGTERM are unblocked. (Perhaps the
|
|
first two can never be blocked anyway?) */
|
|
|
|
sigbus_new.ksa_handler = valid_addr_handler;
|
|
sigbus_new.sa_flags = VKI_SA_ONSTACK | VKI_SA_RESTART;
|
|
sigbus_new.sa_restorer = NULL;
|
|
res = VG_(sigemptyset)( &sigbus_new.sa_mask );
|
|
vg_assert(res == 0);
|
|
|
|
sigsegv_new.ksa_handler = valid_addr_handler;
|
|
sigsegv_new.sa_flags = VKI_SA_ONSTACK | VKI_SA_RESTART;
|
|
sigsegv_new.sa_restorer = NULL;
|
|
res = VG_(sigemptyset)( &sigsegv_new.sa_mask );
|
|
vg_assert(res == 0+0);
|
|
|
|
res = VG_(sigemptyset)( &unblockmask_new );
|
|
res |= VG_(sigaddset)( &unblockmask_new, VKI_SIGBUS );
|
|
res |= VG_(sigaddset)( &unblockmask_new, VKI_SIGSEGV );
|
|
res |= VG_(sigaddset)( &unblockmask_new, VKI_SIGTERM );
|
|
vg_assert(res == 0+0+0);
|
|
|
|
res = VG_(sigaction)( VKI_SIGBUS, &sigbus_new, &sigbus_saved );
|
|
vg_assert(res == 0+0+0+0);
|
|
|
|
res = VG_(sigaction)( VKI_SIGSEGV, &sigsegv_new, &sigsegv_saved );
|
|
vg_assert(res == 0+0+0+0+0);
|
|
|
|
res = VG_(sigprocmask)( VKI_SIG_UNBLOCK, &unblockmask_new, &blockmask_saved );
|
|
vg_assert(res == 0+0+0+0+0+0);
|
|
}
|
|
|
|
static void restore_signals(void)
|
|
{
|
|
Int res;
|
|
|
|
/* Restore signal state to whatever it was before. */
|
|
res = VG_(sigaction)( VKI_SIGBUS, &sigbus_saved, NULL );
|
|
vg_assert(res == 0 +0);
|
|
|
|
res = VG_(sigaction)( VKI_SIGSEGV, &sigsegv_saved, NULL );
|
|
vg_assert(res == 0 +0 +0);
|
|
|
|
res = VG_(sigprocmask)( VKI_SIG_SETMASK, &blockmask_saved, NULL );
|
|
vg_assert(res == 0 +0 +0 +0);
|
|
}
|
|
|
|
/* if false, setup and restore signals for every access */
|
|
#define LAZYSIG 1
|
|
|
|
static Bool is_valid_addr(Addr a)
|
|
{
|
|
static SymType faulted = { TyError };
|
|
static const Bool debug = False;
|
|
volatile Bool ret = False;
|
|
|
|
if ((a > VKI_PAGE_SIZE) && !test_visited(a, &faulted)) {
|
|
if (!LAZYSIG)
|
|
setup_signals();
|
|
|
|
if (__builtin_setjmp(valid_addr_jmpbuf) == 0) {
|
|
volatile UInt *volatile ptr = (volatile UInt *)a;
|
|
|
|
*ptr;
|
|
|
|
ret = True;
|
|
} else {
|
|
/* cache bad addresses in visited table */
|
|
has_visited(a, &faulted);
|
|
ret = False;
|
|
}
|
|
|
|
if (!LAZYSIG)
|
|
restore_signals();
|
|
}
|
|
|
|
if (debug)
|
|
VG_(printf)("is_valid_addr(%p) -> %d\n", a, ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static Int free_varlist(Variable *list)
|
|
{
|
|
Variable *next;
|
|
Int count = 0;
|
|
|
|
for(; list != NULL; list = next) {
|
|
next = list->next;
|
|
count++;
|
|
if (list->name)
|
|
VG_(arena_free)(VG_AR_SYMTAB, list->name);
|
|
VG_(arena_free)(VG_AR_SYMTAB, list);
|
|
}
|
|
return count;
|
|
}
|
|
|
|
/* Composite: struct, union, array
|
|
Non-composite: everything else
|
|
*/
|
|
static inline Bool is_composite(SymType *ty)
|
|
{
|
|
switch(ty->kind) {
|
|
case TyUnion:
|
|
case TyStruct:
|
|
case TyArray:
|
|
return True;
|
|
|
|
default:
|
|
return False;
|
|
}
|
|
}
|
|
|
|
/* There's something at the end of the rainbow */
|
|
static inline Bool is_followable(SymType *ty)
|
|
{
|
|
return ty->kind == TyPointer || is_composite(ty);
|
|
}
|
|
|
|
/* Result buffer */
|
|
static Char *describe_addr_buf;
|
|
static UInt describe_addr_bufidx;
|
|
static UInt describe_addr_bufsz;
|
|
|
|
/* Add a character to the result buffer */
|
|
static void describe_addr_addbuf(HChar c,void *p) {
|
|
if ((describe_addr_bufidx+1) >= describe_addr_bufsz) {
|
|
Char *n;
|
|
|
|
if (describe_addr_bufsz == 0)
|
|
describe_addr_bufsz = 8;
|
|
else
|
|
describe_addr_bufsz *= 2;
|
|
|
|
/* use tool malloc so that the tool can free it */
|
|
n = VG_(malloc)(describe_addr_bufsz);
|
|
if (describe_addr_buf != NULL && describe_addr_bufidx != 0)
|
|
VG_(memcpy)(n, describe_addr_buf, describe_addr_bufidx);
|
|
if (describe_addr_buf != NULL)
|
|
VG_(free)(describe_addr_buf);
|
|
describe_addr_buf = n;
|
|
}
|
|
describe_addr_buf[describe_addr_bufidx++] = c;
|
|
describe_addr_buf[describe_addr_bufidx] = '\0';
|
|
}
|
|
|
|
#define MAX_PLY 7 /* max depth we go */
|
|
#define MAX_ELEMENTS 5000 /* max number of array elements we scan */
|
|
#define MAX_VARS 10000 /* max number of variables total traversed */
|
|
|
|
static const Bool memaccount = False; /* match creates to frees */
|
|
static const Bool debug = False;
|
|
|
|
/* Add a new variable to the list */
|
|
static Bool newvar(Char *name, SymType *ty, Addr valuep, UInt size,
|
|
Variable *var, Int *numvars, Int *created,
|
|
Variable **newlist, Variable **newlistend) {
|
|
Variable *v;
|
|
|
|
/* have we been here before? */
|
|
if (has_visited(valuep, ty))
|
|
return False;
|
|
|
|
/* are we too deep? */
|
|
if (var->distance > MAX_PLY)
|
|
return False;
|
|
|
|
/* have we done too much? */
|
|
if ((*numvars)-- == 0)
|
|
return False;
|
|
|
|
if (memaccount)
|
|
(*created)++;
|
|
|
|
v = VG_(arena_malloc)(VG_AR_SYMTAB, sizeof(*v));
|
|
|
|
if (name)
|
|
v->name = VG_(arena_strdup)(VG_AR_SYMTAB, name);
|
|
else
|
|
v->name = NULL;
|
|
v->type = ML_(st_basetype)(ty, False);
|
|
v->valuep = valuep;
|
|
v->size = size == -1 ? ty->size : size;
|
|
v->container = var;
|
|
v->distance = var->distance + 1;
|
|
v->next = NULL;
|
|
|
|
if (*newlist == NULL)
|
|
*newlist = *newlistend = v;
|
|
else {
|
|
(*newlistend)->next = v;
|
|
*newlistend = v;
|
|
}
|
|
|
|
if (debug)
|
|
VG_(printf)(" --> %d: name=%s type=%p(%s %s) container=%p &val=%p\n",
|
|
v->distance, v->name, v->type, ppkind(v->type->kind),
|
|
v->type->name ? (char *)v->type->name : "",
|
|
v->container, v->valuep);
|
|
return True;
|
|
}
|
|
|
|
static void genstring(Variable *v, Variable *inner, Int *len, Char **ep,
|
|
Char **sp) {
|
|
Variable *c = v->container;
|
|
|
|
if (c != NULL)
|
|
genstring(c, v, len, ep, sp);
|
|
|
|
if (v->name != NULL) {
|
|
*len = VG_(strlen)(v->name);
|
|
VG_(memcpy)(*ep, v->name, *len);
|
|
(*ep) += *len;
|
|
}
|
|
|
|
switch(v->type->kind) {
|
|
case TyPointer:
|
|
/* pointer-to-structure/union handled specially */
|
|
if (inner == NULL ||
|
|
!(inner->type->kind == TyStruct || inner->type->kind == TyUnion)) {
|
|
*--(*sp) = '*';
|
|
*--(*sp) = '(';
|
|
*(*ep)++ = ')';
|
|
}
|
|
break;
|
|
|
|
case TyStruct:
|
|
case TyUnion:
|
|
if (c && c->type->kind == TyPointer) {
|
|
*(*ep)++ = '-';
|
|
*(*ep)++ = '>';
|
|
} else
|
|
*(*ep)++ = '.';
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
Char *VG_(describe_addr)(ThreadId tid, Addr addr)
|
|
{
|
|
Addr eip; /* thread's EIP */
|
|
Variable *list; /* worklist */
|
|
Variable *keeplist; /* container variables */
|
|
Variable *found; /* the chain we found */
|
|
Int created=0, freed=0;
|
|
Int numvars = MAX_VARS;
|
|
|
|
describe_addr_buf = NULL;
|
|
describe_addr_bufidx = 0;
|
|
describe_addr_bufsz = 0;
|
|
|
|
clear_visited();
|
|
|
|
found = NULL;
|
|
keeplist = NULL;
|
|
|
|
eip = VG_(get_IP)(tid);
|
|
list = ML_(get_scope_variables)(tid);
|
|
|
|
if (memaccount) {
|
|
Variable *v;
|
|
|
|
for(v = list; v != NULL; v = v->next)
|
|
created++;
|
|
}
|
|
|
|
if (debug) {
|
|
Char file[100];
|
|
Int line;
|
|
if (!VG_(get_filename_linenum)(eip, file, sizeof(file),
|
|
NULL, 0, NULL, &line))
|
|
file[0] = 0;
|
|
VG_(printf)("describing address %p for tid=%d @ %s:%d\n", addr, tid, file, line);
|
|
}
|
|
|
|
if (LAZYSIG)
|
|
setup_signals();
|
|
|
|
/* breadth-first traversal of all memory visible to the program at
|
|
the current point */
|
|
while(list != NULL && found == NULL) {
|
|
Variable **prev = &list;
|
|
Variable *var, *next;
|
|
Variable *newlist = NULL, *newlistend = NULL;
|
|
|
|
if (debug)
|
|
VG_(printf)("----------------------------------------\n");
|
|
|
|
for(var = list; var != NULL; var = next) {
|
|
SymType *type = var->type;
|
|
Bool keep = False;
|
|
|
|
next = var->next;
|
|
|
|
if (debug)
|
|
VG_(printf)(" %d: name=%s type=%p(%s %s) container=%p &val=%p\n",
|
|
var->distance, var->name,
|
|
var->type, ppkind(var->type->kind),
|
|
var->type->name ? (char *)var->type->name : "",
|
|
var->container, var->valuep);
|
|
|
|
if (0 && has_visited(var->valuep, var->type)) {
|
|
/* advance prev; we're keeping this one on the doomed list */
|
|
prev = &var->next;
|
|
continue;
|
|
}
|
|
|
|
if (!is_composite(var->type) &&
|
|
addr >= var->valuep && addr < (var->valuep + var->size)) {
|
|
/* at hit - remove it from the list, add it to the
|
|
keeplist and set found */
|
|
found = var;
|
|
*prev = var->next;
|
|
var->next = keeplist;
|
|
keeplist = var;
|
|
break;
|
|
}
|
|
|
|
type = ML_(st_basetype)(type, True);
|
|
|
|
switch(type->kind) {
|
|
case TyUnion:
|
|
case TyStruct: {
|
|
Int i;
|
|
|
|
if (debug)
|
|
VG_(printf)(" %d fields\n", type->u.t_struct.nfield);
|
|
for(i = 0; i < type->u.t_struct.nfield; i++) {
|
|
StField *f = &type->u.t_struct.fields[i];
|
|
if(newvar(f->name, f->type, var->valuep + (f->offset / 8),
|
|
(f->size + 7) / 8, var, &numvars, &created, &newlist,
|
|
&newlistend))
|
|
keep = True;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case TyArray: {
|
|
Int i;
|
|
Int offset; /* offset of index for non-0-based arrays */
|
|
Int min, max; /* range of indicies we care about (0 based) */
|
|
SymType *ty = type->u.t_array.type;
|
|
vg_assert(type->u.t_array.idxtype->kind == TyRange);
|
|
|
|
offset = type->u.t_array.idxtype->u.t_range.min;
|
|
min = 0;
|
|
max = type->u.t_array.idxtype->u.t_range.max - offset;
|
|
|
|
if ((max-min+1) == 0) {
|
|
#if SHADOWCHUNK
|
|
/* zero-sized array - look at allocated memory */
|
|
ShadowChunk *sc = findchunk(var->valuep);
|
|
|
|
if (sc != NULL) {
|
|
max = ((sc->data + sc->size - var->valuep) / ty->size) + min;
|
|
if (debug)
|
|
VG_(printf)(" zero sized array: using min=%d max=%d\n",
|
|
min, max);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/* If this array's elements can't take us anywhere useful,
|
|
just look to see if an element itself is being pointed
|
|
to; otherwise just skip the whole thing */
|
|
if (!is_followable(ty)) {
|
|
UInt sz = ty->size * (max+1);
|
|
|
|
if (debug)
|
|
VG_(printf)(" non-followable array (sz=%d): checking addr %p in range %p-%p\n",
|
|
sz, addr, var->valuep, (var->valuep + sz));
|
|
if (ty->size > 0 && addr >= var->valuep && addr <= (var->valuep + sz))
|
|
min = max = (addr - var->valuep) / ty->size;
|
|
else
|
|
break;
|
|
}
|
|
|
|
/* truncate array if it's too big */
|
|
if (max-min+1 > MAX_ELEMENTS)
|
|
max = min+MAX_ELEMENTS;
|
|
|
|
if (debug)
|
|
VG_(printf)(" array index %d - %d\n", min, max);
|
|
for(i = min; i <= max; i++) {
|
|
Char b[10];
|
|
VG_(sprintf)(b, "[%d]", i+offset);
|
|
if(newvar(b, ty, var->valuep + (i * ty->size), -1, var,
|
|
&numvars, &created, &newlist, &newlistend))
|
|
keep = True;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case TyPointer:
|
|
/* follow */
|
|
/* XXX work out a way of telling whether a pointer is
|
|
actually a decayed array, and treat it accordingly */
|
|
if (is_valid_addr(var->valuep))
|
|
if(newvar(NULL, type->u.t_pointer.type, *(Addr *)var->valuep,
|
|
-1, var, &numvars, &created, &newlist, &newlistend))
|
|
keep = True;
|
|
break;
|
|
|
|
case TyUnresolved:
|
|
VG_(printf)("var %s is unresolved (type=%p)\n", var->name, type);
|
|
break;
|
|
|
|
default:
|
|
/* Simple non-composite, non-pointer type */
|
|
break;
|
|
}
|
|
|
|
if (keep) {
|
|
/* ironically, keep means remove it from the list */
|
|
*prev = next;
|
|
|
|
/* being kept - add it if not already there */
|
|
if (keeplist != var) {
|
|
var->next = keeplist;
|
|
keeplist = var;
|
|
}
|
|
} else {
|
|
/* advance prev; we're keeping it on the doomed list */
|
|
prev = &var->next;
|
|
}
|
|
}
|
|
|
|
/* kill old list */
|
|
freed += free_varlist(list);
|
|
list = NULL;
|
|
|
|
if (found) {
|
|
/* kill new list too */
|
|
freed += free_varlist(newlist);
|
|
newlist = newlistend = NULL;
|
|
} else {
|
|
/* new list becomes old list */
|
|
list = newlist;
|
|
}
|
|
}
|
|
|
|
if (LAZYSIG)
|
|
restore_signals();
|
|
|
|
if (found != NULL) {
|
|
Int len = 0;
|
|
Char file[100];
|
|
Int line;
|
|
|
|
/* Try to generate an idiomatic C-like expression from what
|
|
we've found. */
|
|
|
|
{
|
|
Variable *v;
|
|
for(v = found; v != NULL; v = v->container) {
|
|
if (debug)
|
|
VG_(printf)("v=%p (%s) %s\n",
|
|
v, v->name ? v->name : (Char *)"",
|
|
ppkind(v->type->kind));
|
|
|
|
len += (v->name ? VG_(strlen)(v->name) : 0) + 5;
|
|
}
|
|
}
|
|
|
|
/* now that we know how long the expression will be
|
|
(approximately) build it up */
|
|
{
|
|
Char expr[len*2];
|
|
Char *sp = &expr[len]; /* pointer at start of string */
|
|
Char *ep = sp; /* pointer at end of string */
|
|
Bool ptr = True;
|
|
|
|
/* If the result is already a pointer, just use that as the
|
|
value, otherwise generate &(...) around the expression. */
|
|
if (found->container && found->container->type->kind == TyPointer) {
|
|
vg_assert(found->name == NULL);
|
|
|
|
found->name = found->container->name;
|
|
found->container->name = NULL;
|
|
found->container = found->container->container;
|
|
} else {
|
|
bprintf(describe_addr_addbuf, 0, "&(");
|
|
ptr = False;
|
|
}
|
|
|
|
genstring(found, NULL, &len, &ep, &sp);
|
|
|
|
if (!ptr)
|
|
*ep++ = ')';
|
|
|
|
*ep++ = '\0';
|
|
|
|
bprintf(describe_addr_addbuf, 0, sp);
|
|
|
|
if (addr != found->valuep)
|
|
bprintf(describe_addr_addbuf, 0, "+%d", addr - found->valuep);
|
|
|
|
if (VG_(get_filename_linenum)(eip, file, sizeof(file),
|
|
NULL, 0, NULL, &line))
|
|
bprintf(describe_addr_addbuf, 0, " at %s:%d", file, line, addr);
|
|
}
|
|
}
|
|
|
|
freed += free_varlist(keeplist);
|
|
|
|
if (memaccount)
|
|
VG_(printf)("created %d, freed %d\n", created, freed);
|
|
|
|
clear_visited();
|
|
|
|
if (debug)
|
|
VG_(printf)("returning buf=%s\n", describe_addr_buf);
|
|
|
|
return describe_addr_buf;
|
|
}
|
|
#endif /* TEST */
|
|
|
|
/*--------------------------------------------------------------------*/
|
|
/*--- end ---*/
|
|
/*--------------------------------------------------------------------*/
|
|
|
|
/*--------------------------------------------------------------------*/
|
|
/*--- Header for symbol table stuff. priv_symtab.h ---*/
|
|
/*--------------------------------------------------------------------*/
|
|
|
|
/*
|
|
This file is part of Valgrind, a dynamic binary instrumentation
|
|
framework.
|
|
|
|
Copyright (C) 2000-2005 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.
|
|
*/
|
|
|
|
#ifndef __PRIV_SYMTAB_H
|
|
#define __PRIV_SYMTAB_H
|
|
|
|
/* A structure to hold an ELF symbol (very crudely). */
|
|
typedef
|
|
struct {
|
|
Addr addr; /* lowest address of entity */
|
|
UInt size; /* size in bytes */
|
|
Char *name; /* name */
|
|
Addr tocptr; /* ppc64-linux only: value that R2 should have */
|
|
}
|
|
RiSym;
|
|
|
|
/* 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; /* byte size; we catch overflows of this */
|
|
UInt lineno:LINENO_BITS; /* source line number, or zero */
|
|
/* Word 3 */
|
|
Char* filename; /* source filename */
|
|
/* Word 4 */
|
|
Char* dirname; /* source directory name */
|
|
}
|
|
RiLoc;
|
|
|
|
|
|
/* A structure to hold a set of variables in a particular scope */
|
|
typedef struct _Scope Scope; /* a set of symbols in one scope */
|
|
typedef struct _Sym Sym; /* a single symbol */
|
|
typedef struct _ScopeRange ScopeRange; /* a range of code addreses a scope covers */
|
|
|
|
typedef enum {
|
|
SyESPrel, /* on the stack (relative to ESP) */
|
|
SyEBPrel, /* on the stack (relative to EBP) */
|
|
SyReg, /* in a register */
|
|
SyType, /* a type definition */
|
|
SyStatic, /* a static variable */
|
|
SyGlobal, /* a global variable (XXX any different to static
|
|
in an outer scope?) */
|
|
} SyKind;
|
|
|
|
struct _Sym {
|
|
SymType *type; /* type */
|
|
Char *name; /* name */
|
|
SyKind kind; /* kind of symbol */
|
|
|
|
/* a value, depending on kind */
|
|
union {
|
|
OffT offset; /* offset on stack (-ve -> ebp; +ve -> esp) */
|
|
Int regno; /* register number */
|
|
Addr addr; /* static or global address */
|
|
} u;
|
|
};
|
|
|
|
struct _Scope {
|
|
Scope *outer; /* outer (containing) scope */
|
|
UInt nsyms; /* number of symbols in this scope */
|
|
UInt depth; /* depth of scope */
|
|
Sym *syms; /* the symbols */
|
|
};
|
|
|
|
/* A structure to map a scope to a range of code addresses; scopes may
|
|
be broken into multiple ranges (before and after a nested scope) */
|
|
struct _ScopeRange {
|
|
Addr addr; /* start address of this scope */
|
|
Int size; /* length of scope */
|
|
Scope *scope; /* symbols in scope */
|
|
};
|
|
|
|
#define STRCHUNKSIZE (64*1024)
|
|
|
|
|
|
/* A structure to summarise CFI summary 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 = if cfa_sprel then sp+cfa_off else fp+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 )
|
|
*/
|
|
|
|
#define CFIR_UNKNOWN ((UChar)0)
|
|
#define CFIR_SAME ((UChar)1)
|
|
#define CFIR_CFAREL ((UChar)2)
|
|
#define CFIR_MEMCFAREL ((UChar)3)
|
|
|
|
typedef
|
|
struct {
|
|
Addr base;
|
|
UInt len;
|
|
Bool cfa_sprel;
|
|
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;
|
|
}
|
|
CfiSI;
|
|
|
|
extern void ML_(ppCfiSI) ( CfiSI* );
|
|
|
|
|
|
/* A structure which contains information pertaining to one mapped
|
|
text segment. This type is exported only abstractly - in
|
|
pub_tool_debuginfo.h. */
|
|
struct _SegInfo {
|
|
struct _SegInfo* next; /* list of SegInfos */
|
|
|
|
Int ref;
|
|
|
|
/* Description of the mapped segment. */
|
|
Addr start;
|
|
UInt size;
|
|
Char* filename; /* in mallocville */
|
|
OffT foffset;
|
|
Char* soname;
|
|
|
|
/* An expandable array of symbols. */
|
|
RiSym* symtab;
|
|
UInt symtab_used;
|
|
UInt symtab_size;
|
|
/* An expandable array of locations. */
|
|
RiLoc* loctab;
|
|
UInt loctab_used;
|
|
UInt loctab_size;
|
|
/* An expandable array of scope ranges. */
|
|
ScopeRange *scopetab;
|
|
UInt scopetab_used;
|
|
UInt scopetab_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. */
|
|
CfiSI* cfisi;
|
|
UInt cfisi_used;
|
|
UInt cfisi_size;
|
|
Addr cfisi_minaddr;
|
|
Addr cfisi_maxaddr;
|
|
|
|
/* 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;
|
|
Char strtab[STRCHUNKSIZE];
|
|
} *strchunks;
|
|
|
|
/* offset is what we need to add to symbol table entries
|
|
to get the real location of that symbol in memory.
|
|
*/
|
|
OffT offset;
|
|
|
|
/* 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_vma;
|
|
UInt plt_size;
|
|
Addr got_start_vma;
|
|
UInt got_size;
|
|
Addr opd_start_vma;
|
|
UInt opd_size;
|
|
Addr data_start_vma;
|
|
UInt data_size;
|
|
Addr bss_start_vma;
|
|
UInt bss_size;
|
|
|
|
/* data used by stabs parser */
|
|
struct _StabTypeTab *stab_typetab;
|
|
};
|
|
|
|
extern
|
|
Char *ML_(addStr) ( SegInfo* si, Char* str, Int len );
|
|
|
|
extern
|
|
void ML_(addScopeInfo) ( SegInfo* si, Addr this, Addr next, Scope *scope);
|
|
|
|
extern
|
|
void ML_(addLineInfo) ( SegInfo* si,
|
|
Char* filename,
|
|
Char* dirname, /* NULL is allowable */
|
|
Addr this, Addr next, Int lineno, Int entry);
|
|
|
|
extern
|
|
void ML_(addCfiSI) ( SegInfo* si, CfiSI* cfisi );
|
|
|
|
/* Non-fatal -- use vg_panic if terminal. */
|
|
extern
|
|
void ML_(symerr) ( Char* msg );
|
|
|
|
/* --------------------
|
|
Stabs reader
|
|
-------------------- */
|
|
extern
|
|
void ML_(read_debuginfo_stabs) ( SegInfo* si,
|
|
UChar* stabC, Int stab_sz,
|
|
UChar* stabstr, Int stabstr_sz );
|
|
|
|
/* --------------------
|
|
DWARF2 reader
|
|
-------------------- */
|
|
extern
|
|
void ML_(read_debuginfo_dwarf2)
|
|
( SegInfo* si,
|
|
UChar* debuginfo, Int debug_info_sz, /* .debug_info */
|
|
UChar* debugabbrev, /* .debug_abbrev */
|
|
UChar* debugline, Int debug_line_sz, /* .debug_line */
|
|
UChar* debugstr );
|
|
|
|
/* --------------------
|
|
DWARF1 reader
|
|
-------------------- */
|
|
extern
|
|
void ML_(read_debuginfo_dwarf1) ( SegInfo* si,
|
|
UChar* dwarf1d, Int dwarf1d_sz,
|
|
UChar* dwarf1l, Int dwarf1l_sz );
|
|
|
|
/* --------------------
|
|
CFI reader
|
|
-------------------- */
|
|
extern
|
|
void ML_(read_callframe_info_dwarf2)
|
|
( /*OUT*/SegInfo* si, UChar* ehframe, Int ehframe_sz, Addr ehframe_addr );
|
|
|
|
|
|
#endif // __PRIV_SYMTAB_H
|
|
|
|
/*--------------------------------------------------------------------*/
|
|
/*--- end ---*/
|
|
/*--------------------------------------------------------------------*/
|
|
|
|
/*--------------------------------------------------------------------*/
|
|
/*--- Intra-Valgrind interfaces for symtypes.c. priv_symtypes.h ---*/
|
|
/*--------------------------------------------------------------------*/
|
|
|
|
/*
|
|
This file is part of Valgrind, a dynamic binary instrumentation
|
|
framework.
|
|
|
|
Copyright (C) 2000-2005 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.
|
|
*/
|
|
|
|
#ifndef __PRIV_SYMTYPES_H
|
|
#define __PRIV_SYMTYPES_H
|
|
|
|
/* Lets try to make these opaque */
|
|
typedef struct _SymType SymType;
|
|
|
|
/* ------------------------------------------------------------
|
|
Constructors for various SymType nodes
|
|
------------------------------------------------------------ */
|
|
|
|
/* Find the basetype for a given type: that is, if type is a typedef,
|
|
return the typedef'd type. If resolve is true, it will resolve
|
|
unresolved symbols. If type is not a typedef, then this is just
|
|
returns type.
|
|
*/
|
|
SymType *ML_(st_basetype)(SymType *type, Bool resolve);
|
|
|
|
void ML_(st_setname)(SymType *ty, Char *name);
|
|
|
|
typedef void (SymResolver)(SymType *, void *);
|
|
|
|
/* Create an unresolved type */
|
|
SymType *ML_(st_mkunresolved)(SymType *, SymResolver *resolve, void *data);
|
|
|
|
/* update an unresolved type's data */
|
|
void ML_(st_unresolved_setdata)(SymType *, SymResolver *resolve, void *data);
|
|
|
|
Bool ML_(st_isresolved)(SymType *);
|
|
UInt ML_(st_sizeof)(SymType *);
|
|
|
|
/* Unknown type (unparsable) */
|
|
SymType *ML_(st_mkunknown)(SymType *);
|
|
|
|
SymType *ML_(st_mkvoid)(SymType *);
|
|
|
|
SymType *ML_(st_mkint)(SymType *, UInt size, Bool isSigned);
|
|
SymType *ML_(st_mkbool)(SymType *, UInt size);
|
|
SymType *ML_(st_mkchar)(SymType *, Bool isSigned);
|
|
SymType *ML_(st_mkfloat)(SymType *, UInt size);
|
|
SymType *ML_(st_mkdouble)(SymType *, UInt size);
|
|
|
|
SymType *ML_(st_mkpointer)(SymType *, SymType *);
|
|
SymType *ML_(st_mkrange)(SymType *, SymType *, Int min, Int max);
|
|
|
|
SymType *ML_(st_mkstruct)(SymType *, UInt size, UInt nfields);
|
|
SymType *ML_(st_mkunion)(SymType *, UInt size, UInt nfields);
|
|
void ML_(st_addfield)(SymType *, Char *name, SymType *, UInt off, UInt size);
|
|
|
|
SymType *ML_(st_mkenum)(SymType *, UInt ntags);
|
|
SymType *ML_(st_addtag)(SymType *, Char *name, Int val);
|
|
|
|
SymType *ML_(st_mkarray)(SymType *, SymType *idxtype, SymType *artype);
|
|
|
|
SymType *ML_(st_mktypedef)(SymType *, Char *name, SymType *type);
|
|
|
|
Bool ML_(st_isstruct)(SymType *);
|
|
Bool ML_(st_isunion)(SymType *);
|
|
Bool ML_(st_isenum)(SymType *);
|
|
|
|
/* ------------------------------------------------------------
|
|
Interface with symtab.c
|
|
------------------------------------------------------------ */
|
|
|
|
/* Typed value */
|
|
typedef struct _Variable Variable;
|
|
|
|
struct _Variable {
|
|
Char *name; /* name */
|
|
SymType *type; /* type of value */
|
|
Addr valuep; /* pointer to value */
|
|
UInt size; /* size of value */
|
|
UInt distance; /* "distance" from site of interest */
|
|
Variable *next;
|
|
Variable *container;
|
|
};
|
|
|
|
Variable *ML_(get_scope_variables)(ThreadId tid);
|
|
|
|
#endif // __PRIV_SYMTYPES_H
|
|
|
|
/*--------------------------------------------------------------------*/
|
|
/*--- end ---*/
|
|
/*--------------------------------------------------------------------*/
|