blob: dd29452f361cbf77ed9f1a54732cc235c13821f0 [file] [log] [blame]
njnea27e462005-05-31 02:38:09 +00001
njn4bbdc972003-10-16 10:10:55 +00002/*--------------------------------------------------------------------*/
njnea27e462005-05-31 02:38:09 +00003/*--- Extract type info from debug info. symtypes.h ---*/
njn4bbdc972003-10-16 10:10:55 +00004/*--------------------------------------------------------------------*/
5
jsgfcb1d1c02003-10-14 21:55:10 +00006/*
njnb9c427c2004-12-01 14:14:42 +00007 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
njn4bbdc972003-10-16 10:10:55 +00009
njn53612422005-03-12 16:22:54 +000010 Copyright (C) 2000-2005 Julian Seward
njn4bbdc972003-10-16 10:10:55 +000011 jseward@acm.org
12
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of the
16 License, or (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26 02111-1307, USA.
27
28 The GNU General Public License is contained in the file COPYING.
29*/
jsgfcb1d1c02003-10-14 21:55:10 +000030
njnc7561b92005-06-19 01:24:32 +000031#include "pub_core_basics.h"
njnea27e462005-05-31 02:38:09 +000032#include "pub_core_debuginfo.h"
njnf4c50162005-06-20 14:18:12 +000033#include "pub_core_debuglog.h" // For VG_(debugLog_vprintf)
njn97405b22005-06-02 03:39:33 +000034#include "pub_core_libcbase.h"
njn132bfcc2005-06-04 19:16:06 +000035#include "pub_core_libcassert.h"
njn36a20fa2005-06-03 03:08:39 +000036#include "pub_core_libcprint.h"
njnde62cbf2005-06-10 22:08:14 +000037#include "pub_core_libcsignal.h"
njnf536bbb2005-06-13 04:21:38 +000038#include "pub_core_machine.h"
njnaf1d7df2005-06-11 01:31:52 +000039#include "pub_core_mallocfree.h"
njnf4c50162005-06-20 14:18:12 +000040
njnea27e462005-05-31 02:38:09 +000041#include "priv_symtypes.h"
jsgfcb1d1c02003-10-14 21:55:10 +000042
43typedef enum {
44 TyUnknown, /* unknown type */
45 TyUnresolved, /* unresolved type */
46 TyError, /* error type */
47
48 TyVoid, /* void */
49
50 TyInt, /* integer */
51 TyBool, /* boolean */
52 TyChar, /* character */
53 TyFloat, /* float */
54
55 TyRange, /* type subrange */
56
57 TyEnum, /* enum */
58
59 TyPointer, /* pointer */
60 TyArray, /* array */
61 TyStruct, /* structure/class */
62 TyUnion, /* union */
63
64 TyTypedef /* typedef */
65} TyKind;
66
67static const Char *ppkind(TyKind k)
68{
69 switch(k) {
70#define S(x) case x: return #x
71 S(TyUnknown);
72 S(TyUnresolved);
73 S(TyError);
74 S(TyVoid);
75 S(TyInt);
76 S(TyBool);
77 S(TyChar);
78 S(TyRange);
79 S(TyFloat);
80 S(TyEnum);
81 S(TyPointer);
82 S(TyArray);
83 S(TyStruct);
84 S(TyUnion);
85 S(TyTypedef);
86#undef S
87 default:
88 return "Ty???";
89 }
90}
91
92/* struct/union field */
93typedef struct _StField {
94 UInt offset; /* offset into structure (0 for union) (in bits) */
95 UInt size; /* size (in bits) */
96 SymType *type; /* type of element */
97 Char *name; /* name of element */
98} StField;
99
100/* enum tag */
101typedef struct _EnTag {
102 const Char *name; /* name */
103 UInt val; /* value */
104} EnTag;
105
106struct _SymType {
107 TyKind kind; /* type descriminator */
108 UInt size; /* sizeof(type) */
109 Char *name; /* useful name */
110
111 union {
112 /* TyInt,TyBool,TyChar */
113 struct {
114 Bool issigned; /* signed or not */
115 } t_scalar;
116
117 /* TyFloat */
118 struct {
119 Bool isdouble; /* is double prec */
120 } t_float;
121
122 /* TyRange */
123 struct {
124 Int min;
125 Int max;
126 SymType *type;
127 } t_range;
128
129 /* TyPointer */
130 struct {
131 SymType *type; /* *type */
132 } t_pointer;
133
134 /* TyArray */
135 struct {
136 SymType *idxtype;
137 SymType *type;
138 } t_array;
139
140 /* TyEnum */
141 struct {
142 UInt ntag; /* number of tags */
143 EnTag *tags; /* tags */
144 } t_enum;
145
146 /* TyStruct, TyUnion */
147 struct {
148 UInt nfield; /* number of fields */
149 UInt nfieldalloc; /* number of fields allocated */
150 StField *fields; /* fields */
151 } t_struct;
152
153 /* TyTypedef */
154 struct {
155 SymType *type; /* type */
156 } t_typedef;
157
158 /* TyUnresolved - reference to unresolved type */
159 struct {
160 /* some kind of symtab reference */
161 SymResolver *resolver; /* symtab reader's resolver */
162 void *data; /* data for resolver */
163 } t_unresolved;
mueller5ed88f22004-01-06 16:02:29 +0000164 } u;
jsgfcb1d1c02003-10-14 21:55:10 +0000165};
166
167
sewardj7eb7c582005-06-23 01:02:53 +0000168Bool ML_(st_isstruct)(SymType *ty)
jsgfcb1d1c02003-10-14 21:55:10 +0000169{
170 return ty->kind == TyStruct;
171}
172
sewardj7eb7c582005-06-23 01:02:53 +0000173Bool ML_(st_isunion)(SymType *ty)
jsgfcb1d1c02003-10-14 21:55:10 +0000174{
175 return ty->kind == TyUnion;
176}
177
sewardj7eb7c582005-06-23 01:02:53 +0000178Bool ML_(st_isenum)(SymType *ty)
jsgfcb1d1c02003-10-14 21:55:10 +0000179{
180 return ty->kind == TyEnum;
181}
182
183static inline SymType *alloc(SymType *st)
184{
185 if (st == NULL) {
186 st = VG_(arena_malloc)(VG_AR_SYMTAB, sizeof(*st));
187 st->kind = TyUnknown;
188 st->name = NULL;
189 }
190
191 return st;
192}
193
194static void resolve(SymType *st)
195{
196 if (st->kind != TyUnresolved)
197 return;
198
mueller5ed88f22004-01-06 16:02:29 +0000199 (*st->u.t_unresolved.resolver)(st, st->u.t_unresolved.data);
jsgfcb1d1c02003-10-14 21:55:10 +0000200
201 if (st->kind == TyUnresolved)
202 st->kind = TyError;
203}
204
sewardj7eb7c582005-06-23 01:02:53 +0000205SymType *ML_(st_mkunresolved)(SymType *st, SymResolver *resolver, void *data)
jsgfcb1d1c02003-10-14 21:55:10 +0000206{
207 st = alloc(st);
208
209 vg_assert(st->kind == TyUnresolved || st->kind == TyUnknown);
210
211 st->kind = TyUnresolved;
212 st->size = 0;
mueller5ed88f22004-01-06 16:02:29 +0000213 st->u.t_unresolved.resolver = resolver;
214 st->u.t_unresolved.data = data;
jsgfcb1d1c02003-10-14 21:55:10 +0000215
216 return st;
217}
218
sewardj7eb7c582005-06-23 01:02:53 +0000219void ML_(st_unresolved_setdata)(SymType *st, SymResolver *resolver, void *data)
jsgfcb1d1c02003-10-14 21:55:10 +0000220{
221 if (st->kind != TyUnresolved)
222 return;
223
mueller5ed88f22004-01-06 16:02:29 +0000224 st->u.t_unresolved.resolver = resolver;
225 st->u.t_unresolved.data = data;
jsgfcb1d1c02003-10-14 21:55:10 +0000226}
227
sewardj7eb7c582005-06-23 01:02:53 +0000228Bool ML_(st_isresolved)(SymType *st)
jsgfcb1d1c02003-10-14 21:55:10 +0000229{
230 return st->kind != TyUnresolved;
231}
232
sewardj7eb7c582005-06-23 01:02:53 +0000233void ML_(st_setname)(SymType *st, Char *name)
jsgfcb1d1c02003-10-14 21:55:10 +0000234{
235 if (st->name != NULL)
236 st->name = name;
237}
238
sewardj7eb7c582005-06-23 01:02:53 +0000239SymType *ML_(st_mkvoid)(SymType *st)
jsgfcb1d1c02003-10-14 21:55:10 +0000240{
241 st = alloc(st);
242
243 vg_assert(st->kind == TyUnresolved || st->kind == TyUnknown);
244
245 st->kind = TyVoid;
246 st->size = 1; /* for address calculations */
247 st->name = "void";
248 return st;
249}
250
sewardj7eb7c582005-06-23 01:02:53 +0000251SymType *ML_(st_mkint)(SymType *st, UInt size, Bool isSigned)
jsgfcb1d1c02003-10-14 21:55:10 +0000252{
253 st = alloc(st);
254
255 vg_assert(st->kind == TyUnresolved || st->kind == TyUnknown);
256
257 st->kind = TyInt;
258 st->size = size;
mueller5ed88f22004-01-06 16:02:29 +0000259 st->u.t_scalar.issigned = isSigned;
jsgfcb1d1c02003-10-14 21:55:10 +0000260
261 return st;
262}
263
sewardj7eb7c582005-06-23 01:02:53 +0000264SymType *ML_(st_mkfloat)(SymType *st, UInt size)
jsgfcb1d1c02003-10-14 21:55:10 +0000265{
266 st = alloc(st);
267
268 vg_assert(st->kind == TyUnresolved || st->kind == TyUnknown);
269
270 st->kind = TyFloat;
271 st->size = size;
mueller5ed88f22004-01-06 16:02:29 +0000272 st->u.t_scalar.issigned = True;
jsgfcb1d1c02003-10-14 21:55:10 +0000273
274 return st;
275}
276
sewardj7eb7c582005-06-23 01:02:53 +0000277SymType *ML_(st_mkbool)(SymType *st, UInt size)
jsgfcb1d1c02003-10-14 21:55:10 +0000278{
279 st = alloc(st);
280
281 vg_assert(st->kind == TyUnresolved || st->kind == TyUnknown);
282
283 st->kind = TyBool;
284 st->size = size;
285
286 return st;
287}
288
289
sewardj7eb7c582005-06-23 01:02:53 +0000290SymType *ML_(st_mkpointer)(SymType *st, SymType *ptr)
jsgfcb1d1c02003-10-14 21:55:10 +0000291{
292 st = alloc(st);
293
294 vg_assert(st->kind == TyUnresolved || st->kind == TyUnknown);
295
296 st->kind = TyPointer;
297 st->size = sizeof(void *);
mueller5ed88f22004-01-06 16:02:29 +0000298 st->u.t_pointer.type = ptr;
jsgfcb1d1c02003-10-14 21:55:10 +0000299
300 return st;
301}
302
sewardj7eb7c582005-06-23 01:02:53 +0000303SymType *ML_(st_mkrange)(SymType *st, SymType *ty, Int min, Int max)
jsgfcb1d1c02003-10-14 21:55:10 +0000304{
305 st = alloc(st);
306
307 vg_assert(st->kind == TyUnresolved || st->kind == TyUnknown);
308
309 st->kind = TyRange;
310 st->size = 0; /* ? */
mueller5ed88f22004-01-06 16:02:29 +0000311 st->u.t_range.type = ty;
312 st->u.t_range.min = min;
313 st->u.t_range.max = max;
jsgfcb1d1c02003-10-14 21:55:10 +0000314
315 return st;
316}
317
sewardj7eb7c582005-06-23 01:02:53 +0000318SymType *ML_(st_mkstruct)(SymType *st, UInt size, UInt nfields)
jsgfcb1d1c02003-10-14 21:55:10 +0000319{
320 st = alloc(st);
321
322 vg_assert(st->kind == TyUnresolved || st->kind == TyUnknown || st->kind == TyStruct);
323
mueller5ed88f22004-01-06 16:02:29 +0000324 vg_assert(st->kind != TyStruct || st->u.t_struct.nfield == 0);
jsgfcb1d1c02003-10-14 21:55:10 +0000325
326 st->kind = TyStruct;
327 st->size = size;
mueller5ed88f22004-01-06 16:02:29 +0000328 st->u.t_struct.nfield = 0;
329 st->u.t_struct.nfieldalloc = nfields;
jsgfcb1d1c02003-10-14 21:55:10 +0000330 if (nfields != 0)
mueller5ed88f22004-01-06 16:02:29 +0000331 st->u.t_struct.fields = VG_(arena_malloc)(VG_AR_SYMTAB, sizeof(StField) * nfields);
jsgfcb1d1c02003-10-14 21:55:10 +0000332 else
mueller5ed88f22004-01-06 16:02:29 +0000333 st->u.t_struct.fields = NULL;
jsgfcb1d1c02003-10-14 21:55:10 +0000334
335 return st;
336}
337
sewardj7eb7c582005-06-23 01:02:53 +0000338SymType *ML_(st_mkunion)(SymType *st, UInt size, UInt nfields)
jsgfcb1d1c02003-10-14 21:55:10 +0000339{
340 st = alloc(st);
341
342 vg_assert(st->kind == TyUnresolved || st->kind == TyUnknown || st->kind == TyUnion);
343
mueller5ed88f22004-01-06 16:02:29 +0000344 vg_assert(st->kind != TyUnion || st->u.t_struct.nfield == 0);
jsgfcb1d1c02003-10-14 21:55:10 +0000345
346 st->kind = TyUnion;
347 st->size = size;
mueller5ed88f22004-01-06 16:02:29 +0000348 st->u.t_struct.nfield = 0;
349 st->u.t_struct.nfieldalloc = nfields;
jsgfcb1d1c02003-10-14 21:55:10 +0000350 if (nfields != 0)
mueller5ed88f22004-01-06 16:02:29 +0000351 st->u.t_struct.fields = VG_(arena_malloc)(VG_AR_SYMTAB, sizeof(StField) * nfields);
jsgfcb1d1c02003-10-14 21:55:10 +0000352 else
mueller5ed88f22004-01-06 16:02:29 +0000353 st->u.t_struct.fields = NULL;
jsgfcb1d1c02003-10-14 21:55:10 +0000354
355 return st;
356}
357
sewardj7eb7c582005-06-23 01:02:53 +0000358void ML_(st_addfield)(SymType *st, Char *name, SymType *type, UInt off, UInt size)
jsgfcb1d1c02003-10-14 21:55:10 +0000359{
360 StField *f;
361
362 vg_assert(st->kind == TyStruct || st->kind == TyUnion);
363
mueller5ed88f22004-01-06 16:02:29 +0000364 if (st->u.t_struct.nfieldalloc == st->u.t_struct.nfield) {
jsgfcb1d1c02003-10-14 21:55:10 +0000365 StField *n = VG_(arena_malloc)(VG_AR_SYMTAB,
mueller5ed88f22004-01-06 16:02:29 +0000366 sizeof(StField) * (st->u.t_struct.nfieldalloc + 2));
367 VG_(memcpy)(n, st->u.t_struct.fields, sizeof(*n) * st->u.t_struct.nfield);
368 if (st->u.t_struct.fields != NULL)
369 VG_(arena_free)(VG_AR_SYMTAB, st->u.t_struct.fields);
370 st->u.t_struct.nfieldalloc++;
371 st->u.t_struct.fields = n;
jsgfcb1d1c02003-10-14 21:55:10 +0000372 }
373
mueller5ed88f22004-01-06 16:02:29 +0000374 f = &st->u.t_struct.fields[st->u.t_struct.nfield++];
jsgfcb1d1c02003-10-14 21:55:10 +0000375 f->name = name;
376 f->type = type;
377 f->offset = off;
378 f->size = size;
379}
380
381
sewardj7eb7c582005-06-23 01:02:53 +0000382SymType *ML_(st_mkenum)(SymType *st, UInt ntags)
jsgfcb1d1c02003-10-14 21:55:10 +0000383{
384 st = alloc(st);
385
386 vg_assert(st->kind == TyUnresolved || st->kind == TyUnknown || st->kind == TyEnum);
387
388 st->kind = TyEnum;
mueller5ed88f22004-01-06 16:02:29 +0000389 st->u.t_enum.ntag = 0;
390 st->u.t_enum.tags = NULL;
jsgfcb1d1c02003-10-14 21:55:10 +0000391
392 return st;
393}
394
sewardj7eb7c582005-06-23 01:02:53 +0000395SymType *ML_(st_mkarray)(SymType *st, SymType *idxtype, SymType *type)
jsgfcb1d1c02003-10-14 21:55:10 +0000396{
397 st = alloc(st);
398
399 vg_assert(st->kind == TyUnresolved || st->kind == TyUnknown);
400
401 st->kind = TyArray;
mueller5ed88f22004-01-06 16:02:29 +0000402 st->u.t_array.type = type;
403 st->u.t_array.idxtype = idxtype;
jsgfcb1d1c02003-10-14 21:55:10 +0000404
405 return st;
406}
407
sewardj7eb7c582005-06-23 01:02:53 +0000408SymType *ML_(st_mktypedef)(SymType *st, Char *name, SymType *type)
jsgfcb1d1c02003-10-14 21:55:10 +0000409{
410 st = alloc(st);
411
thughesb9019d82004-10-07 08:21:38 +0000412 vg_assert(st != type);
jsgfcb1d1c02003-10-14 21:55:10 +0000413 vg_assert(st->kind == TyUnresolved || st->kind == TyUnknown ||
414 st->kind == TyStruct || st->kind == TyUnion ||
415 st->kind == TyTypedef);
416
417 st->kind = TyTypedef;
418 st->name = name;
mueller5ed88f22004-01-06 16:02:29 +0000419 st->u.t_typedef.type = type;
jsgfcb1d1c02003-10-14 21:55:10 +0000420
421 return st;
422}
423
424
sewardj7eb7c582005-06-23 01:02:53 +0000425SymType *ML_(st_basetype)(SymType *type, Bool do_resolve)
jsgfcb1d1c02003-10-14 21:55:10 +0000426{
427 while (type->kind == TyTypedef || (do_resolve && type->kind == TyUnresolved)) {
428 if (do_resolve)
429 resolve(type);
430
431 if (type->kind == TyTypedef)
mueller5ed88f22004-01-06 16:02:29 +0000432 type = type->u.t_typedef.type;
jsgfcb1d1c02003-10-14 21:55:10 +0000433 }
434
435 return type;
436}
437
sewardj7eb7c582005-06-23 01:02:53 +0000438UInt ML_(st_sizeof)(SymType *ty)
jsgfcb1d1c02003-10-14 21:55:10 +0000439{
440 return ty->size;
441}
442
443#ifndef TEST
444/*
445 Hash of visited addresses, so we don't get stuck in loops. It isn't
446 simply enough to keep track of addresses, since we need to interpret
447 the memory according to the type. If a given location has multiple
448 pointers with different types (for example, void * and struct foo *),
449 then we need to look at it under each type.
450*/
451struct visited {
452 Addr a;
453 SymType *ty;
454 struct visited *next;
455};
456
457#define VISIT_HASHSZ 1021
458
459static struct visited *visit_hash[VISIT_HASHSZ];
460
461static inline Bool test_visited(Addr a, SymType *type)
462{
463 struct visited *v;
464 UInt b = (UInt)a % VISIT_HASHSZ;
465 Bool ret = False;
466
467 for(v = visit_hash[b]; v != NULL; v = v->next) {
468 if (v->a == a && v->ty == type) {
469 ret = True;
470 break;
471 }
472 }
473
474 return ret;
475}
476
477static Bool has_visited(Addr a, SymType *type)
478{
479 static const Bool debug = False;
480 Bool ret;
481
482 ret = test_visited(a, type);
483
484 if (!ret) {
485 UInt b = (UInt)a % VISIT_HASHSZ;
486 struct visited * v = VG_(arena_malloc)(VG_AR_SYMTAB, sizeof(*v));
487
488 v->a = a;
489 v->ty = type;
490 v->next = visit_hash[b];
491 visit_hash[b] = v;
492 }
493
494 if (debug)
495 VG_(printf)("has_visited(a=%p, ty=%p) -> %d\n", a, type, ret);
496
497 return ret;
498}
499
500static void clear_visited(void)
501{
502 UInt i;
503
504 for(i = 0; i < VISIT_HASHSZ; i++) {
505 struct visited *v, *n;
506 for(v = visit_hash[i]; v != NULL; v = n) {
507 n = v->next;
508 VG_(arena_free)(VG_AR_SYMTAB, v);
509 }
510 visit_hash[i] = NULL;
511 }
512}
513
sewardj1cf558c2005-04-25 01:36:56 +0000514static
515void bprintf(void (*send)(HChar, void*), void *send_arg, const Char *fmt, ...)
jsgfcb1d1c02003-10-14 21:55:10 +0000516{
517 va_list vargs;
518
519 va_start(vargs, fmt);
sewardj1cf558c2005-04-25 01:36:56 +0000520 VG_(debugLog_vprintf)(send, send_arg, fmt, vargs);
jsgfcb1d1c02003-10-14 21:55:10 +0000521 va_end(vargs);
522}
523
524#define SHADOWCHUNK 0 /* no longer have a core allocator */
525
526#if SHADOWCHUNK
527static ShadowChunk *findchunk(Addr a)
528{
529 Bool find(ShadowChunk *sc) {
530 return a >= sc->data && a < (sc->data+sc->size);
531 }
532 return VG_(any_matching_mallocd_ShadowChunks)(find);
533}
534#endif
535
nethercote73b526f2004-10-31 18:48:21 +0000536static struct vki_sigaction sigbus_saved;
537static struct vki_sigaction sigsegv_saved;
538static vki_sigset_t blockmask_saved;
jsgfcb1d1c02003-10-14 21:55:10 +0000539static jmp_buf valid_addr_jmpbuf;
540
541static void valid_addr_handler(int sig)
542{
543 //VG_(printf)("OUCH! %d\n", sig);
544 __builtin_longjmp(valid_addr_jmpbuf, 1);
545}
546
547/* catch badness signals because we're going to be
548 playing around in untrusted memory */
549static void setup_signals(void)
550{
551 Int res;
nethercote73b526f2004-10-31 18:48:21 +0000552 struct vki_sigaction sigbus_new;
553 struct vki_sigaction sigsegv_new;
554 vki_sigset_t unblockmask_new;
jsgfcb1d1c02003-10-14 21:55:10 +0000555
556 /* Temporarily install a new sigsegv and sigbus handler, and make
557 sure SIGBUS, SIGSEGV and SIGTERM are unblocked. (Perhaps the
558 first two can never be blocked anyway?) */
559
560 sigbus_new.ksa_handler = valid_addr_handler;
nethercote73b526f2004-10-31 18:48:21 +0000561 sigbus_new.sa_flags = VKI_SA_ONSTACK | VKI_SA_RESTART;
562 sigbus_new.sa_restorer = NULL;
563 res = VG_(sigemptyset)( &sigbus_new.sa_mask );
jsgfcb1d1c02003-10-14 21:55:10 +0000564 vg_assert(res == 0);
565
566 sigsegv_new.ksa_handler = valid_addr_handler;
nethercote73b526f2004-10-31 18:48:21 +0000567 sigsegv_new.sa_flags = VKI_SA_ONSTACK | VKI_SA_RESTART;
568 sigsegv_new.sa_restorer = NULL;
569 res = VG_(sigemptyset)( &sigsegv_new.sa_mask );
jsgfcb1d1c02003-10-14 21:55:10 +0000570 vg_assert(res == 0+0);
571
nethercote73b526f2004-10-31 18:48:21 +0000572 res = VG_(sigemptyset)( &unblockmask_new );
573 res |= VG_(sigaddset)( &unblockmask_new, VKI_SIGBUS );
574 res |= VG_(sigaddset)( &unblockmask_new, VKI_SIGSEGV );
575 res |= VG_(sigaddset)( &unblockmask_new, VKI_SIGTERM );
jsgfcb1d1c02003-10-14 21:55:10 +0000576 vg_assert(res == 0+0+0);
577
nethercote73b526f2004-10-31 18:48:21 +0000578 res = VG_(sigaction)( VKI_SIGBUS, &sigbus_new, &sigbus_saved );
jsgfcb1d1c02003-10-14 21:55:10 +0000579 vg_assert(res == 0+0+0+0);
580
nethercote73b526f2004-10-31 18:48:21 +0000581 res = VG_(sigaction)( VKI_SIGSEGV, &sigsegv_new, &sigsegv_saved );
jsgfcb1d1c02003-10-14 21:55:10 +0000582 vg_assert(res == 0+0+0+0+0);
583
nethercote73b526f2004-10-31 18:48:21 +0000584 res = VG_(sigprocmask)( VKI_SIG_UNBLOCK, &unblockmask_new, &blockmask_saved );
jsgfcb1d1c02003-10-14 21:55:10 +0000585 vg_assert(res == 0+0+0+0+0+0);
586}
587
588static void restore_signals(void)
589{
590 Int res;
591
592 /* Restore signal state to whatever it was before. */
nethercote73b526f2004-10-31 18:48:21 +0000593 res = VG_(sigaction)( VKI_SIGBUS, &sigbus_saved, NULL );
jsgfcb1d1c02003-10-14 21:55:10 +0000594 vg_assert(res == 0 +0);
595
nethercote73b526f2004-10-31 18:48:21 +0000596 res = VG_(sigaction)( VKI_SIGSEGV, &sigsegv_saved, NULL );
jsgfcb1d1c02003-10-14 21:55:10 +0000597 vg_assert(res == 0 +0 +0);
598
nethercote73b526f2004-10-31 18:48:21 +0000599 res = VG_(sigprocmask)( VKI_SIG_SETMASK, &blockmask_saved, NULL );
jsgfcb1d1c02003-10-14 21:55:10 +0000600 vg_assert(res == 0 +0 +0 +0);
601}
602
603/* if false, setup and restore signals for every access */
604#define LAZYSIG 1
605
606static Bool is_valid_addr(Addr a)
607{
608 static SymType faulted = { TyError };
609 static const Bool debug = False;
610 volatile Bool ret = False;
611
nethercote55c09082004-11-04 19:33:51 +0000612 if ((a > VKI_PAGE_SIZE) && !test_visited(a, &faulted)) {
jsgfcb1d1c02003-10-14 21:55:10 +0000613 if (!LAZYSIG)
614 setup_signals();
615
616 if (__builtin_setjmp(valid_addr_jmpbuf) == 0) {
617 volatile UInt *volatile ptr = (volatile UInt *)a;
618
619 *ptr;
620
621 ret = True;
622 } else {
623 /* cache bad addresses in visited table */
624 has_visited(a, &faulted);
625 ret = False;
626 }
627
628 if (!LAZYSIG)
629 restore_signals();
630 }
631
632 if (debug)
633 VG_(printf)("is_valid_addr(%p) -> %d\n", a, ret);
634
635 return ret;
636}
637
638static Int free_varlist(Variable *list)
639{
640 Variable *next;
641 Int count = 0;
642
643 for(; list != NULL; list = next) {
644 next = list->next;
645 count++;
646 if (list->name)
647 VG_(arena_free)(VG_AR_SYMTAB, list->name);
648 VG_(arena_free)(VG_AR_SYMTAB, list);
649 }
650 return count;
651}
652
653/* Composite: struct, union, array
654 Non-composite: everything else
655 */
656static inline Bool is_composite(SymType *ty)
657{
658 switch(ty->kind) {
659 case TyUnion:
660 case TyStruct:
661 case TyArray:
662 return True;
663
664 default:
665 return False;
666 }
667}
668
669/* There's something at the end of the rainbow */
670static inline Bool is_followable(SymType *ty)
671{
672 return ty->kind == TyPointer || is_composite(ty);
673}
674
thughes4ad52d02004-06-27 17:37:21 +0000675/* Result buffer */
676static Char *describe_addr_buf;
677static UInt describe_addr_bufidx;
678static UInt describe_addr_bufsz;
679
680/* Add a character to the result buffer */
sewardj1cf558c2005-04-25 01:36:56 +0000681static void describe_addr_addbuf(HChar c,void *p) {
thughes4ad52d02004-06-27 17:37:21 +0000682 if ((describe_addr_bufidx+1) >= describe_addr_bufsz) {
683 Char *n;
684
685 if (describe_addr_bufsz == 0)
686 describe_addr_bufsz = 8;
687 else
688 describe_addr_bufsz *= 2;
689
nethercote996901a2004-08-03 13:29:09 +0000690 /* use tool malloc so that the tool can free it */
thughes4ad52d02004-06-27 17:37:21 +0000691 n = VG_(malloc)(describe_addr_bufsz);
692 if (describe_addr_buf != NULL && describe_addr_bufidx != 0)
693 VG_(memcpy)(n, describe_addr_buf, describe_addr_bufidx);
694 if (describe_addr_buf != NULL)
695 VG_(free)(describe_addr_buf);
696 describe_addr_buf = n;
697 }
698 describe_addr_buf[describe_addr_bufidx++] = c;
699 describe_addr_buf[describe_addr_bufidx] = '\0';
700}
701
jsgfcb1d1c02003-10-14 21:55:10 +0000702#define MAX_PLY 7 /* max depth we go */
703#define MAX_ELEMENTS 5000 /* max number of array elements we scan */
704#define MAX_VARS 10000 /* max number of variables total traversed */
705
706Char *VG_(describe_addr)(ThreadId tid, Addr addr)
707{
708 static const Bool debug = False;
709 static const Bool memaccount = False; /* match creates to frees */
710 Addr eip; /* thread's EIP */
711 Variable *list; /* worklist */
712 Variable *keeplist; /* container variables */
713 Variable *found; /* the chain we found */
jsgfcb1d1c02003-10-14 21:55:10 +0000714 Int created=0, freed=0;
715 Int numvars = MAX_VARS;
716
thughes4ad52d02004-06-27 17:37:21 +0000717 describe_addr_buf = NULL;
718 describe_addr_bufidx = 0;
719 describe_addr_bufsz = 0;
jsgfcb1d1c02003-10-14 21:55:10 +0000720
721 clear_visited();
722
723 found = NULL;
724 keeplist = NULL;
725
njn67516132005-03-22 04:02:43 +0000726 eip = VG_(get_IP)(tid);
sewardj7eb7c582005-06-23 01:02:53 +0000727 list = ML_(get_scope_variables)(tid);
jsgfcb1d1c02003-10-14 21:55:10 +0000728
729 if (memaccount) {
730 Variable *v;
731
732 for(v = list; v != NULL; v = v->next)
733 created++;
734 }
735
736 if (debug) {
737 Char file[100];
738 Int line;
sewardj7cee6f92005-06-13 17:39:06 +0000739 if (!VG_(get_filename_linenum)(eip, file, sizeof(file),
740 NULL, 0, NULL, &line))
jsgfcb1d1c02003-10-14 21:55:10 +0000741 file[0] = 0;
742 VG_(printf)("describing address %p for tid=%d @ %s:%d\n", addr, tid, file, line);
743 }
744
745 if (LAZYSIG)
746 setup_signals();
747
748 /* breadth-first traversal of all memory visible to the program at
749 the current point */
750 while(list != NULL && found == NULL) {
751 Variable **prev = &list;
752 Variable *var, *next;
753 Variable *newlist = NULL, *newlistend = NULL;
754
755 if (debug)
756 VG_(printf)("----------------------------------------\n");
757
758 for(var = list; var != NULL; var = next) {
759 SymType *type = var->type;
760 Bool keep = False;
761
762 /* Add a new variable to the list */
njnb18cf2b2005-10-14 13:48:54 +0000763 // (the declaration avoids a compiler warning)
sewardj681b8812005-10-15 00:58:26 +0000764 //static void newvar(Char *name, SymType *ty, Addr valuep, UInt size);
njnb18cf2b2005-10-14 13:48:54 +0000765 void newvar(Char *name, SymType *ty, Addr valuep, UInt size) {
jsgfcb1d1c02003-10-14 21:55:10 +0000766 Variable *v;
767
768 /* have we been here before? */
769 if (has_visited(valuep, ty))
770 return;
771
772 /* are we too deep? */
773 if (var->distance > MAX_PLY)
774 return;
775
776 /* have we done too much? */
777 if (numvars-- == 0)
778 return;
779
780 if (memaccount)
781 created++;
782
783 v = VG_(arena_malloc)(VG_AR_SYMTAB, sizeof(*v));
784
785 if (name)
786 v->name = VG_(arena_strdup)(VG_AR_SYMTAB, name);
787 else
788 v->name = NULL;
sewardj7eb7c582005-06-23 01:02:53 +0000789 v->type = ML_(st_basetype)(ty, False);
jsgfcb1d1c02003-10-14 21:55:10 +0000790 v->valuep = valuep;
791 v->size = size == -1 ? ty->size : size;
792 v->container = var;
793 v->distance = var->distance + 1;
794 v->next = NULL;
795
796 if (newlist == NULL)
797 newlist = newlistend = v;
798 else {
799 newlistend->next = v;
800 newlistend = v;
801 }
802
803 if (debug)
804 VG_(printf)(" --> %d: name=%s type=%p(%s %s) container=%p &val=%p\n",
805 v->distance, v->name,
806 v->type, ppkind(v->type->kind),
807 v->type->name ? (char *)v->type->name : "",
808 v->container, v->valuep);
809 keep = True;
810 return;
811 }
812
813 next = var->next;
814
815 if (debug)
816 VG_(printf)(" %d: name=%s type=%p(%s %s) container=%p &val=%p\n",
817 var->distance, var->name,
818 var->type, ppkind(var->type->kind),
819 var->type->name ? (char *)var->type->name : "",
820 var->container, var->valuep);
821
822 if (0 && has_visited(var->valuep, var->type)) {
823 /* advance prev; we're keeping this one on the doomed list */
824 prev = &var->next;
825 continue;
826 }
827
828 if (!is_composite(var->type) &&
829 addr >= var->valuep && addr < (var->valuep + var->size)) {
830 /* at hit - remove it from the list, add it to the
831 keeplist and set found */
832 found = var;
833 *prev = var->next;
834 var->next = keeplist;
835 keeplist = var;
836 break;
837 }
838
sewardj7eb7c582005-06-23 01:02:53 +0000839 type = ML_(st_basetype)(type, True);
jsgfcb1d1c02003-10-14 21:55:10 +0000840
841 switch(type->kind) {
842 case TyUnion:
843 case TyStruct: {
844 Int i;
845
846 if (debug)
mueller5ed88f22004-01-06 16:02:29 +0000847 VG_(printf)(" %d fields\n", type->u.t_struct.nfield);
848 for(i = 0; i < type->u.t_struct.nfield; i++) {
849 StField *f = &type->u.t_struct.fields[i];
jsgfcb1d1c02003-10-14 21:55:10 +0000850 newvar(f->name, f->type, var->valuep + (f->offset / 8), (f->size + 7) / 8);
851 }
852 break;
853 }
854
855 case TyArray: {
856 Int i;
857 Int offset; /* offset of index for non-0-based arrays */
858 Int min, max; /* range of indicies we care about (0 based) */
mueller5ed88f22004-01-06 16:02:29 +0000859 SymType *ty = type->u.t_array.type;
860 vg_assert(type->u.t_array.idxtype->kind == TyRange);
jsgfcb1d1c02003-10-14 21:55:10 +0000861
mueller5ed88f22004-01-06 16:02:29 +0000862 offset = type->u.t_array.idxtype->u.t_range.min;
jsgfcb1d1c02003-10-14 21:55:10 +0000863 min = 0;
mueller5ed88f22004-01-06 16:02:29 +0000864 max = type->u.t_array.idxtype->u.t_range.max - offset;
jsgfcb1d1c02003-10-14 21:55:10 +0000865
866 if ((max-min+1) == 0) {
867#if SHADOWCHUNK
868 /* zero-sized array - look at allocated memory */
869 ShadowChunk *sc = findchunk(var->valuep);
870
871 if (sc != NULL) {
872 max = ((sc->data + sc->size - var->valuep) / ty->size) + min;
873 if (debug)
874 VG_(printf)(" zero sized array: using min=%d max=%d\n",
875 min, max);
876 }
877#endif
878 }
879
880 /* If this array's elements can't take us anywhere useful,
881 just look to see if an element itself is being pointed
882 to; otherwise just skip the whole thing */
883 if (!is_followable(ty)) {
884 UInt sz = ty->size * (max+1);
885
886 if (debug)
887 VG_(printf)(" non-followable array (sz=%d): checking addr %p in range %p-%p\n",
888 sz, addr, var->valuep, (var->valuep + sz));
sewardjb5f6f512005-03-10 23:59:00 +0000889 if (ty->size > 0 && addr >= var->valuep && addr <= (var->valuep + sz))
jsgfcb1d1c02003-10-14 21:55:10 +0000890 min = max = (addr - var->valuep) / ty->size;
891 else
892 break;
893 }
894
895 /* truncate array if it's too big */
896 if (max-min+1 > MAX_ELEMENTS)
897 max = min+MAX_ELEMENTS;
898
899 if (debug)
900 VG_(printf)(" array index %d - %d\n", min, max);
901 for(i = min; i <= max; i++) {
902 Char b[10];
903 VG_(sprintf)(b, "[%d]", i+offset);
904 newvar(b, ty, var->valuep + (i * ty->size), -1);
905 }
906
907 break;
908 }
909
910 case TyPointer:
911 /* follow */
912 /* XXX work out a way of telling whether a pointer is
913 actually a decayed array, and treat it accordingly */
914 if (is_valid_addr(var->valuep))
mueller5ed88f22004-01-06 16:02:29 +0000915 newvar(NULL, type->u.t_pointer.type, *(Addr *)var->valuep, -1);
jsgfcb1d1c02003-10-14 21:55:10 +0000916 break;
917
918 case TyUnresolved:
919 VG_(printf)("var %s is unresolved (type=%p)\n", var->name, type);
920 break;
921
922 default:
923 /* Simple non-composite, non-pointer type */
924 break;
925 }
926
927 if (keep) {
928 /* ironically, keep means remove it from the list */
929 *prev = next;
930
931 /* being kept - add it if not already there */
932 if (keeplist != var) {
933 var->next = keeplist;
934 keeplist = var;
935 }
936 } else {
937 /* advance prev; we're keeping it on the doomed list */
938 prev = &var->next;
939 }
940 }
941
942 /* kill old list */
943 freed += free_varlist(list);
944 list = NULL;
945
946 if (found) {
947 /* kill new list too */
948 freed += free_varlist(newlist);
949 newlist = newlistend = NULL;
950 } else {
951 /* new list becomes old list */
952 list = newlist;
953 }
954 }
955
956 if (LAZYSIG)
957 restore_signals();
958
959 if (found != NULL) {
960 Int len = 0;
961 Char file[100];
962 Int line;
963
964 /* Try to generate an idiomatic C-like expression from what
965 we've found. */
966
967 {
968 Variable *v;
969 for(v = found; v != NULL; v = v->container) {
970 if (debug)
971 VG_(printf)("v=%p (%s) %s\n",
972 v, v->name ? v->name : (Char *)"",
973 ppkind(v->type->kind));
974
975 len += (v->name ? VG_(strlen)(v->name) : 0) + 5;
976 }
977 }
978
979 /* now that we know how long the expression will be
980 (approximately) build it up */
981 {
982 Char expr[len*2];
983 Char *sp = &expr[len]; /* pointer at start of string */
984 Char *ep = sp; /* pointer at end of string */
sewardj681b8812005-10-15 00:58:26 +0000985 // static void genstring(Variable *v, Variable *inner); // avoid warning
njnb18cf2b2005-10-14 13:48:54 +0000986 void genstring(Variable *v, Variable *inner) {
jsgfcb1d1c02003-10-14 21:55:10 +0000987 Variable *c = v->container;
988
989 if (c != NULL)
990 genstring(c, v);
991
992 if (v->name != NULL) {
993 len = VG_(strlen)(v->name);
994 VG_(memcpy)(ep, v->name, len);
995 ep += len;
996 }
997
998 switch(v->type->kind) {
999 case TyPointer:
1000 /* pointer-to-structure/union handled specially */
1001 if (inner == NULL ||
1002 !(inner->type->kind == TyStruct || inner->type->kind == TyUnion)) {
1003 *--sp = '*';
1004 *--sp = '(';
1005 *ep++ = ')';
1006 }
1007 break;
1008
1009 case TyStruct:
1010 case TyUnion:
1011 if (c && c->type->kind == TyPointer) {
1012 *ep++ = '-';
1013 *ep++ = '>';
1014 } else
1015 *ep++ = '.';
1016 break;
1017
1018 default:
1019 break;
1020 }
1021 }
1022
1023 {
1024 Bool ptr = True;
1025
1026 /* If the result is already a pointer, just use that as
1027 the value, otherwise generate &(...) around the
1028 expression. */
1029 if (found->container && found->container->type->kind == TyPointer) {
1030 vg_assert(found->name == NULL);
1031
1032 found->name = found->container->name;
1033 found->container->name = NULL;
1034 found->container = found->container->container;
1035 } else {
sewardjb5f6f512005-03-10 23:59:00 +00001036 bprintf(describe_addr_addbuf, 0, "&(");
jsgfcb1d1c02003-10-14 21:55:10 +00001037 ptr = False;
1038 }
1039
1040 genstring(found, NULL);
1041
1042 if (!ptr)
1043 *ep++ = ')';
1044 }
1045
1046 *ep++ = '\0';
1047
sewardjb5f6f512005-03-10 23:59:00 +00001048 bprintf(describe_addr_addbuf, 0, sp);
jsgfcb1d1c02003-10-14 21:55:10 +00001049
1050 if (addr != found->valuep)
sewardjb5f6f512005-03-10 23:59:00 +00001051 bprintf(describe_addr_addbuf, 0, "+%d", addr - found->valuep);
jsgfcb1d1c02003-10-14 21:55:10 +00001052
sewardj7cee6f92005-06-13 17:39:06 +00001053 if (VG_(get_filename_linenum)(eip, file, sizeof(file),
1054 NULL, 0, NULL, &line))
sewardjb5f6f512005-03-10 23:59:00 +00001055 bprintf(describe_addr_addbuf, 0, " at %s:%d", file, line, addr);
jsgfcb1d1c02003-10-14 21:55:10 +00001056 }
1057 }
1058
1059 freed += free_varlist(keeplist);
1060
1061 if (memaccount)
1062 VG_(printf)("created %d, freed %d\n", created, freed);
1063
1064 clear_visited();
1065
1066 if (debug)
thughes4ad52d02004-06-27 17:37:21 +00001067 VG_(printf)("returning buf=%s\n", describe_addr_buf);
jsgfcb1d1c02003-10-14 21:55:10 +00001068
thughes4ad52d02004-06-27 17:37:21 +00001069 return describe_addr_buf;
jsgfcb1d1c02003-10-14 21:55:10 +00001070}
1071#endif /* TEST */
njn4bbdc972003-10-16 10:10:55 +00001072
1073/*--------------------------------------------------------------------*/
njnea27e462005-05-31 02:38:09 +00001074/*--- end ---*/
njn4bbdc972003-10-16 10:10:55 +00001075/*--------------------------------------------------------------------*/