2 /*--------------------------------------------------------------------*/
3 /*--- Read stabs debug info. readstabs.c ---*/
4 /*--------------------------------------------------------------------*/
7 This file is part of Valgrind, a dynamic binary instrumentation
10 Copyright (C) 2000-2010 Julian Seward
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.
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.
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
28 The GNU General Public License is contained in the file COPYING.
31 #if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_l4re)
34 Stabs reader greatly improved by Nick Nethercote, Apr 02.
35 This module was also extensively hacked on by Jeremy Fitzhardinge
39 #include "pub_core_basics.h"
40 #include "pub_core_debuginfo.h"
41 #include "pub_core_libcbase.h"
42 #include "pub_core_libcassert.h"
43 #include "pub_core_libcprint.h"
44 #include "pub_core_xarray.h"
45 #include "priv_misc.h" /* dinfo_zalloc/free/strdup */
46 #include "priv_tytypes.h"
47 #include "priv_d3basics.h"
48 #include "priv_storage.h"
49 #include "priv_readstabs.h" /* self */
51 /* --- !!! --- EXTERNAL HEADERS start --- !!! --- */
52 #if defined(VGO_linux)
53 # include <a.out.h> /* stabs defns */
54 #elif defined(VGO_darwin)
55 # include <mach-o/nlist.h>
56 # define n_other n_sect
58 # define nlist nlist_64
60 #elif defined(VGO_l4re)
70 unsigned long n_value;
75 /* --- !!! --- EXTERNAL HEADERS end --- !!! --- */
77 /*------------------------------------------------------------*/
78 /*--- Read STABS format debug info. ---*/
79 /*------------------------------------------------------------*/
81 /* Stabs entry types, from:
82 * The "stabs" debug format
83 * Menapace, Kingdon and MacKenzie
86 typedef enum { N_UNDEF = 0, /* undefined symbol, new stringtab */
87 N_GSYM = 32, /* Global symbol */
88 N_FUN = 36, /* Function start or end */
89 N_STSYM = 38, /* Data segment file-scope variable */
90 N_LCSYM = 40, /* BSS segment file-scope variable */
91 N_RSYM = 64, /* Register variable */
92 N_SLINE = 68, /* Source line number */
93 N_SO = 100, /* Source file path and name */
94 N_LSYM = 128, /* Stack variable or type */
95 N_BINCL = 130, /* Beginning of an include file */
96 N_SOL = 132, /* Include file name */
97 N_PSYM = 160, /* Function parameter */
98 N_EINCL = 162, /* End of an include file */
99 N_LBRAC = 192, /* Start of lexical block */
100 N_EXCL = 194, /* Placeholder for an include file */
101 N_RBRAC = 224 /* End of lexical block */
105 /* Read stabs-format debug info. This is all rather horrible because
106 stabs is a underspecified, kludgy hack.
108 void ML_(read_debuginfo_stabs) ( DebugInfo* di,
109 UChar* stabC, Int stab_sz,
110 UChar* stabstr, Int stabstr_sz )
112 const Bool debug = False;
113 const Bool contdebug = False;
116 struct nlist* stab = (struct nlist*)stabC;
117 UChar *next_stabstr = NULL;
118 /* state for various things */
120 Addr start; /* start address */
121 Addr end; /* end address */
122 Int line; /* first line */
123 } func = { 0, 0, -1 };
127 } file = { NULL, True };
129 Int prev; /* prev line */
130 Int no; /* current line */
131 Int ovf; /* line wrap */
132 Addr addr; /* start of this line */
133 Bool first; /* first line in function */
134 } line = { 0, 0, 0, 0, False };
136 /* Ok. It all looks plausible. Go on and read debug data.
137 stab kinds: 100 N_SO a source file name
138 68 N_SLINE a source line number
139 36 N_FUN start of a function
141 In this loop, we maintain a current file name, updated as
142 N_SO/N_SOLs appear, and a current function base address,
143 updated as N_FUNs appear. Based on that, address ranges for
144 N_SLINEs are calculated, and stuffed into the line info table.
146 Finding the instruction address range covered by an N_SLINE is
147 complicated; see the N_SLINE case below.
149 file.name = ML_(addStr)(di,"???", -1);
151 n_stab_entries = stab_sz/(int)sizeof(struct nlist);
153 for (i = 0; i < n_stab_entries; i++) {
154 const struct nlist *st = &stab[i];
157 if (di->trace_symtab) {
158 VG_(printf) ( "%2d type=%d othr=%d desc=%d "
159 "value=0x%x strx=%d %s\n", i,
160 st->n_type, st->n_other, st->n_desc,
162 (Int)st->n_un.n_strx,
163 stabstr + st->n_un.n_strx );
166 /* handle continued string stabs */
172 Bool qcontinuing = False;
175 qstringidx = st->n_un.n_strx;
176 string = stabstr + qstringidx;
177 qlen = VG_(strlen)(string);
181 && (qcontinuing || string[qlen-1] == '\\')) {
182 /* Gak, we have a continuation. Skip forward through
183 subsequent stabs to gather all the parts of the
184 continuation. Increment i, but keep st pointing at
187 qcontinuing = string[qlen-1] == '\\';
189 /* remove trailing \ */
190 while (string[qlen-1] == '\\' && qlen > 0)
194 VG_(printf)("found extension string: \"%s\" "
195 "len=%d(%c) idx=%d buflen=%d\n",
196 string, qlen, string[qlen-1], qidx, qbuflen);
198 /* XXX this is silly. The si->strtab should have a way of
199 appending to the last added string... */
200 if ((qidx + qlen) >= qbuflen) {
205 while ((qidx + qlen) >= qbuflen)
207 n = ML_(dinfo_zalloc)("di.readstabs.rds.1", qbuflen);
208 VG_(memcpy)(n, qbuf, qidx);
211 ML_(dinfo_free)(qbuf);
215 VG_(memcpy)(&qbuf[qidx], string, qlen);
219 VG_(printf)("working buf=\"%s\"\n", qbuf);
223 if (i >= n_stab_entries)
226 if (stab[i].n_un.n_strx) {
227 string = stabstr + stab[i].n_un.n_strx;
228 qlen = VG_(strlen)(string);
236 i--; /* overstepped */
237 string = ML_(addStr)(di, qbuf, qidx);
238 ML_(dinfo_free)(qbuf);
240 VG_(printf)("made composite: \"%s\"\n", string);
246 /* new string table base */
247 if (next_stabstr != NULL) {
248 stabstr_sz -= next_stabstr - stabstr;
249 stabstr = next_stabstr;
250 if (stabstr_sz <= 0) {
251 VG_(printf)(" @@ bad stabstr size %d\n", stabstr_sz);
255 next_stabstr = stabstr + st->n_value;
268 case N_SOL: /* sub-source (include) file */
270 VG_(message)(Vg_UserMsg,
271 "Warning: file %s is very big (> 65535 lines) "
272 "Line numbers and annotation for this file might "
273 "be wrong. Sorry.\n",
277 case N_SO: { /* new source file */
279 UInt len = VG_(strlen)(nm);
280 Addr addr = func.start + st->n_value;
282 if (line.addr != 0) {
283 /* finish off previous line */
284 ML_(addLineInfo)(di, file.name, NULL, line.addr,
285 addr, line.no + line.ovf * LINENO_OVERFLOW, i);
288 /* reset line state */
294 if (len > 0 && nm[len-1] != '/') {
295 file.name = ML_(addStr)(di, nm, -1);
297 VG_(printf)("new source: %s\n", file.name);
299 file.name = ML_(addStr)(di, "?1\0", -1);
304 case N_SLINE: { /* line info */
305 Addr addr = func.start + st->n_value;
307 if (line.addr != 0) {
308 /* there was a previous */
309 ML_(addLineInfo)(di, file.name, NULL, line.addr,
310 addr, line.no + line.ovf * LINENO_OVERFLOW, i);
315 line.no = (Int)((UShort)st->n_desc);
317 if (line.prev > line.no + OVERFLOW_DIFFERENCE && file.same) {
318 VG_(message)(Vg_DebugMsg,
319 "Line number overflow detected (%d --> %d) in %s\n",
320 line.prev, line.no, file.name);
325 /* This is pretty horrible. If this is the first line of
326 the function, then bind any unbound symbols to the arg
327 scope, since they're probably arguments. */
331 /* remember first line of function */
332 if (func.start != 0) {
339 case N_FUN: { /* function start/end */
340 Addr addr = 0; /* end address for prev line/scope */
342 /* if this the end of the function or we haven't
343 previously finished the previous function... */
344 if (*string == '\0' || func.start != 0) {
345 /* end of function */
348 /* end line at end of function */
349 addr = func.start + st->n_value;
351 /* now between functions */
354 // XXXX DEAD POINT XXXX
357 if (*string != '\0') {
361 /* line ends at start of next function */
362 addr = di->text_debug_bias + st->n_value;
368 ML_(addLineInfo)(di, file.name, NULL, line.addr,
369 addr, line.no + line.ovf * LINENO_OVERFLOW, i);
390 case N_GSYM: /* global variable */
391 case N_STSYM: /* static in data segment */
392 case N_LCSYM: /* static in bss segment */
393 case N_PSYM: /* function parameter */
394 case N_LSYM: /* stack variable */
395 case N_RSYM: /* register variable */
401 #endif // defined(VGO_linux) || defined(VGO_darwin)
403 /*--------------------------------------------------------------------*/
405 /*--------------------------------------------------------------------*/