+++ /dev/null
-
-/*--------------------------------------------------------------------*/
-/*--- 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 ---*/
-/*--------------------------------------------------------------------*/
+++ /dev/null
-
-/*--------------------------------------------------------------------*/
-/*--- Read stabs debug info. readstabs.c ---*/
-/*--------------------------------------------------------------------*/
-
-/*
- This file is part of Valgrind, a dynamic binary instrumentation
- framework.
-
- Copyright (C) 2000-2013 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.
-*/
-
-/* "on Linux (except android), or on Darwin" */
-#if (defined(VGO_linux) && \
- !(defined(VGPV_arm_linux_android) || defined(VGPV_x86_linux_android) \
- || defined(VGPV_mips32_linux_android)) \
- || defined(VGO_darwin))
-
-#include "pub_core_basics.h"
-#include "pub_core_debuginfo.h"
-#include "pub_core_libcbase.h"
-#include "pub_core_libcassert.h"
-#include "pub_core_libcprint.h"
-#include "pub_core_xarray.h"
-#include "priv_misc.h" /* dinfo_zalloc/free/strdup */
-#include "priv_image.h"
-#include "priv_tytypes.h"
-#include "priv_d3basics.h"
-#include "priv_storage.h"
-#include "priv_readstabs.h" /* self */
-
-/* --- !!! --- EXTERNAL HEADERS start --- !!! --- */
-#if defined(VGO_linux)
-/* stabs symbol list entry definition. */
-struct nlist {
- union {
- char *n_name;
- struct nlist *n_next;
- long n_strx;
- } n_un;
- unsigned char n_type;
- char n_other;
- short n_desc;
- unsigned long n_value;
-};
-#elif defined(VGO_darwin)
-# include <mach-o/nlist.h>
-# define n_other n_sect
-# if VG_WORDSIZE == 8
-# define nlist nlist_64
-# endif
-#else
-# error "Unknown OS"
-#endif
-/* --- !!! --- EXTERNAL HEADERS end --- !!! --- */
-
-/*------------------------------------------------------------*/
-/*--- Read STABS format debug info. ---*/
-/*------------------------------------------------------------*/
-
-/* Stabs entry types, from:
- * The "stabs" debug format
- * Menapace, Kingdon and MacKenzie
- * Cygnus Support
- */
-typedef enum { N_UNDEF = 0, /* undefined symbol, new stringtab */
- N_GSYM = 32, /* Global symbol */
- N_FUN = 36, /* Function start or end */
- N_STSYM = 38, /* Data segment file-scope variable */
- N_LCSYM = 40, /* BSS segment file-scope variable */
- N_RSYM = 64, /* Register variable */
- N_SLINE = 68, /* Source line number */
- N_SO = 100, /* Source file path and name */
- N_LSYM = 128, /* Stack variable or type */
- N_BINCL = 130, /* Beginning of an include file */
- N_SOL = 132, /* Include file name */
- N_PSYM = 160, /* Function parameter */
- N_EINCL = 162, /* End of an include file */
- N_LBRAC = 192, /* Start of lexical block */
- N_EXCL = 194, /* Placeholder for an include file */
- N_RBRAC = 224 /* End of lexical block */
- } stab_types;
-
-
-/* Read stabs-format debug info. This is all rather horrible because
- stabs is a underspecified, kludgy hack.
-*/
-void ML_(read_debuginfo_stabs) ( DebugInfo* di,
- UChar* stabC, Int stab_sz,
- HChar* stabstr, Int stabstr_sz )
-{
- Int i;
- Int n_stab_entries;
- struct nlist* stab = (struct nlist*)stabC;
- HChar *next_stabstr = NULL;
- /* state for various things */
- struct {
- Addr start; /* start address */
- Addr end; /* end address */
- Int line; /* first line */
- } func = { 0, 0, -1 };
- struct {
- HChar *name;
- Bool same;
- } file = { NULL, True };
- struct {
- Int prev; /* prev line */
- Int no; /* current line */
- Int ovf; /* line wrap */
- Addr addr; /* start of this line */
- Bool first; /* first line in function */
- } line = { 0, 0, 0, 0, False };
-
- vg_assert (0);
- /* Stab reader broken since debuginfo server (revision 13440)
- See #if 0 for call to ML_(read_debuginfo_stabs) in readelf.c.
- If ever it is repaired, file.name above should be replaced by a fndn_ix
- for performance reasons. */
-
- /* Ok. It all looks plausible. Go on and read debug data.
- stab kinds: 100 N_SO a source file name
- 68 N_SLINE a source line number
- 36 N_FUN start of a function
-
- In this loop, we maintain a current file name, updated as
- N_SO/N_SOLs appear, and a current function base address,
- updated as N_FUNs appear. Based on that, address ranges for
- N_SLINEs are calculated, and stuffed into the line info table.
-
- Finding the instruction address range covered by an N_SLINE is
- complicated; see the N_SLINE case below.
- */
- file.name = ML_(addStr)(di,"???", -1);
-
- n_stab_entries = stab_sz/(int)sizeof(struct nlist);
-
- TRACE_SYMTAB("\n--- Reading STABS (%d entries) ---\n", n_stab_entries);
-
- for (i = 0; i < n_stab_entries; i++) {
- const struct nlist *st = &stab[i];
- HChar *string;
-
- TRACE_SYMTAB("%2d type=%d othr=%d desc=%d "
- "value=0x%x strx=%d %s\n", i,
- st->n_type, st->n_other, st->n_desc,
- (Int)st->n_value,
- (Int)st->n_un.n_strx,
- stabstr + st->n_un.n_strx );
-
- /* handle continued string stabs */
- {
- Int qbuflen = 0;
- Int qidx = 0;
- HChar* qbuf = NULL;
- Int qlen;
- Bool qcontinuing = False;
- UInt qstringidx;
-
- qstringidx = st->n_un.n_strx;
- string = stabstr + qstringidx;
- qlen = VG_(strlen)(string);
-
- while (string
- && qlen > 0
- && (qcontinuing || string[qlen-1] == '\\')) {
- /* Gak, we have a continuation. Skip forward through
- subsequent stabs to gather all the parts of the
- continuation. Increment i, but keep st pointing at
- current stab. */
-
- qcontinuing = string[qlen-1] == '\\';
-
- /* remove trailing \ */
- while (string[qlen-1] == '\\' && qlen > 0)
- qlen--;
-
- TRACE_SYMTAB("cont: found extension string: \"%s\" "
- "len=%d(%c) idx=%d buflen=%d\n",
- string, qlen, string[qlen-1], qidx, qbuflen);
-
- /* XXX this is silly. The si->strtab should have a way of
- appending to the last added string... */
- if ((qidx + qlen) >= qbuflen) {
- HChar *n;
-
- if (qbuflen == 0)
- qbuflen = 16;
- while ((qidx + qlen) >= qbuflen)
- qbuflen *= 2;
- n = ML_(dinfo_zalloc)("di.readstabs.rds.1", qbuflen);
- VG_(memcpy)(n, qbuf, qidx);
-
- if (qbuf != NULL)
- ML_(dinfo_free)(qbuf);
- qbuf = n;
- }
-
- VG_(memcpy)(&qbuf[qidx], string, qlen);
- qidx += qlen;
- if (di->trace_symtab) {
- qbuf[qidx] = '\0';
- TRACE_SYMTAB("cont: working buf=\"%s\"\n", qbuf);
- }
-
- i++;
- if (i >= n_stab_entries)
- break;
-
- if (stab[i].n_un.n_strx) {
- string = stabstr + stab[i].n_un.n_strx;
- qlen = VG_(strlen)(string);
- } else {
- string = NULL;
- qlen = 0;
- }
- }
-
- if (qbuf != NULL) {
- i--; /* overstepped */
- string = ML_(addStr)(di, qbuf, qidx);
- ML_(dinfo_free)(qbuf);
- TRACE_SYMTAB("cont: made composite: \"%s\"\n", string);
- }
- }
-
- switch(st->n_type) {
- case N_UNDEF:
- /* new string table base */
- if (next_stabstr != NULL) {
- stabstr_sz -= next_stabstr - stabstr;
- stabstr = next_stabstr;
- if (stabstr_sz <= 0) {
- VG_(printf)(" @@ bad stabstr size %d\n", stabstr_sz);
- return;
- }
- }
- next_stabstr = stabstr + st->n_value;
- break;
-
- case N_BINCL: {
- break;
- }
-
- case N_EINCL:
- break;
-
- case N_EXCL:
- break;
-
- case N_SOL: /* sub-source (include) file */
- if (line.ovf != 0)
- VG_(message)(Vg_UserMsg,
- "Warning: file %s is very big (> 65535 lines) "
- "Line numbers and annotation for this file might "
- "be wrong. Sorry.\n",
- file.name);
- /* FALLTHROUGH */
-
- case N_SO: { /* new source file */
- HChar *nm = string;
- UInt len = VG_(strlen)(nm);
- Addr addr = func.start + st->n_value;
-
- if (line.addr != 0) {
- /* finish off previous line */
- ML_(addLineInfo)(di,
- ML_(addFnDn) (di,
- file.name,
- NULL),
- line.addr,
- addr, line.no + line.ovf * LINENO_OVERFLOW, i);
- }
-
- /* reset line state */
- line.ovf = 0;
- line.addr = 0;
- line.prev = 0;
- line.no = 0;
-
- if (len > 0 && nm[len-1] != '/') {
- file.name = ML_(addStr)(di, nm, -1);
- TRACE_SYMTAB("new source: %s\n", file.name);
- } else if (len == 0)
- file.name = ML_(addStr)(di, "?1\0", -1);
-
- break;
- }
-
- case N_SLINE: { /* line info */
- Addr addr = func.start + st->n_value;
-
- if (line.addr != 0) {
- /* there was a previous */
- ML_(addLineInfo)(di,
- ML_(addFnDn)(di,
- file.name,
- NULL),
- line.addr,
- addr, line.no + line.ovf * LINENO_OVERFLOW, i);
- }
-
- line.addr = addr;
- line.prev = line.no;
- line.no = (Int)((UShort)st->n_desc);
-
- if (line.prev > line.no + OVERFLOW_DIFFERENCE && file.same) {
- VG_(message)(Vg_DebugMsg,
- "Line number overflow detected (%d --> %d) in %s\n",
- line.prev, line.no, file.name);
- line.ovf++;
- }
- file.same = True;
-
- /* This is pretty horrible. If this is the first line of
- the function, then bind any unbound symbols to the arg
- scope, since they're probably arguments. */
- if (line.first) {
- line.first = False;
-
- /* remember first line of function */
- if (func.start != 0) {
- func.line = line.no;
- }
- }
- break;
- }
-
- case N_FUN: { /* function start/end */
- Addr addr = 0; /* end address for prev line/scope */
-
- /* if this the end of the function or we haven't
- previously finished the previous function... */
- if (*string == '\0' || func.start != 0) {
- /* end of function */
- line.first = False;
-
- /* end line at end of function */
- addr = func.start + st->n_value;
-
- /* now between functions */
- func.start = 0;
-
- // XXXX DEAD POINT XXXX
- }
-
- if (*string != '\0') {
- /* new function */
- line.first = True;
-
- /* line ends at start of next function */
- addr = di->text_debug_bias + st->n_value;
-
- func.start = addr;
- }
-
- if (line.addr) {
- ML_(addLineInfo)(di,
- ML_(addFnDn) (di,
- file.name,
- NULL),
- line.addr,
- addr, line.no + line.ovf * LINENO_OVERFLOW, i);
- line.addr = 0;
- }
-
- //DEAD POINT
- //DEAD POINT
- break;
- }
-
- case N_LBRAC: {
- /* open new scope */
- // DEAD POINT
- break;
- }
-
- case N_RBRAC: {
- /* close scope */
- // DEAD POINT
- break;
- }
-
- case N_GSYM: /* global variable */
- case N_STSYM: /* static in data segment */
- case N_LCSYM: /* static in bss segment */
- case N_PSYM: /* function parameter */
- case N_LSYM: /* stack variable */
- case N_RSYM: /* register variable */
- break;
- }
- }
-}
-
-#endif /* (defined(VGO_linux) && !defined(VGPV_*_linux_android)) \
- || defined(VGO_darwin) */
-
-/*--------------------------------------------------------------------*/
-/*--- end ---*/
-/*--------------------------------------------------------------------*/