1 2 /*--------------------------------------------------------------------*/ 3 /*--- Read stabs debug info. readstabs.c ---*/ 4 /*--------------------------------------------------------------------*/ 5 6 /* 7 This file is part of Valgrind, a dynamic binary instrumentation 8 framework. 9 10 Copyright (C) 2000-2010 Julian Seward 11 jseward (at) 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 */ 30 31 #if defined(VGO_linux) || defined(VGO_darwin) 32 33 /* 34 Stabs reader greatly improved by Nick Nethercote, Apr 02. 35 This module was also extensively hacked on by Jeremy Fitzhardinge 36 and Tom Hughes. 37 */ 38 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 */ 50 51 /* --- !!! --- EXTERNAL HEADERS start --- !!! --- */ 52 #if defined(VGO_linux) 53 #ifdef ANDROID 54 # include <linux/a.out.h> 55 #else 56 # include <a.out.h> /* stabs defns */ 57 #endif 58 #elif defined(VGO_darwin) 59 # include <mach-o/nlist.h> 60 # define n_other n_sect 61 # if VG_WORDSIZE == 8 62 # define nlist nlist_64 63 # endif 64 #else 65 # error "Unknown OS" 66 #endif 67 /* --- !!! --- EXTERNAL HEADERS end --- !!! --- */ 68 69 /*------------------------------------------------------------*/ 70 /*--- Read STABS format debug info. ---*/ 71 /*------------------------------------------------------------*/ 72 73 /* Stabs entry types, from: 74 * The "stabs" debug format 75 * Menapace, Kingdon and MacKenzie 76 * Cygnus Support 77 */ 78 typedef enum { N_UNDEF = 0, /* undefined symbol, new stringtab */ 79 N_GSYM = 32, /* Global symbol */ 80 N_FUN = 36, /* Function start or end */ 81 N_STSYM = 38, /* Data segment file-scope variable */ 82 N_LCSYM = 40, /* BSS segment file-scope variable */ 83 N_RSYM = 64, /* Register variable */ 84 N_SLINE = 68, /* Source line number */ 85 N_SO = 100, /* Source file path and name */ 86 N_LSYM = 128, /* Stack variable or type */ 87 N_BINCL = 130, /* Beginning of an include file */ 88 N_SOL = 132, /* Include file name */ 89 N_PSYM = 160, /* Function parameter */ 90 N_EINCL = 162, /* End of an include file */ 91 N_LBRAC = 192, /* Start of lexical block */ 92 N_EXCL = 194, /* Placeholder for an include file */ 93 N_RBRAC = 224 /* End of lexical block */ 94 } stab_types; 95 96 97 /* Read stabs-format debug info. This is all rather horrible because 98 stabs is a underspecified, kludgy hack. 99 */ 100 void ML_(read_debuginfo_stabs) ( DebugInfo* di, 101 UChar* stabC, Int stab_sz, 102 UChar* stabstr, Int stabstr_sz ) 103 { 104 const Bool debug = False; 105 const Bool contdebug = False; 106 Int i; 107 Int n_stab_entries; 108 struct nlist* stab = (struct nlist*)stabC; 109 UChar *next_stabstr = NULL; 110 /* state for various things */ 111 struct { 112 Addr start; /* start address */ 113 Addr end; /* end address */ 114 Int line; /* first line */ 115 } func = { 0, 0, -1 }; 116 struct { 117 Char *name; 118 Bool same; 119 } file = { NULL, True }; 120 struct { 121 Int prev; /* prev line */ 122 Int no; /* current line */ 123 Int ovf; /* line wrap */ 124 Addr addr; /* start of this line */ 125 Bool first; /* first line in function */ 126 } line = { 0, 0, 0, 0, False }; 127 128 /* Ok. It all looks plausible. Go on and read debug data. 129 stab kinds: 100 N_SO a source file name 130 68 N_SLINE a source line number 131 36 N_FUN start of a function 132 133 In this loop, we maintain a current file name, updated as 134 N_SO/N_SOLs appear, and a current function base address, 135 updated as N_FUNs appear. Based on that, address ranges for 136 N_SLINEs are calculated, and stuffed into the line info table. 137 138 Finding the instruction address range covered by an N_SLINE is 139 complicated; see the N_SLINE case below. 140 */ 141 file.name = ML_(addStr)(di,"???", -1); 142 143 n_stab_entries = stab_sz/(int)sizeof(struct nlist); 144 145 for (i = 0; i < n_stab_entries; i++) { 146 const struct nlist *st = &stab[i]; 147 Char *string; 148 149 if (di->trace_symtab) { 150 VG_(printf) ( "%2d type=%d othr=%d desc=%d " 151 "value=0x%x strx=%d %s\n", i, 152 st->n_type, st->n_other, st->n_desc, 153 (Int)st->n_value, 154 (Int)st->n_un.n_strx, 155 stabstr + st->n_un.n_strx ); 156 } 157 158 /* handle continued string stabs */ 159 { 160 Int qbuflen = 0; 161 Int qidx = 0; 162 Char* qbuf = NULL; 163 Int qlen; 164 Bool qcontinuing = False; 165 UInt qstringidx; 166 167 qstringidx = st->n_un.n_strx; 168 string = stabstr + qstringidx; 169 qlen = VG_(strlen)(string); 170 171 while (string 172 && qlen > 0 173 && (qcontinuing || string[qlen-1] == '\\')) { 174 /* Gak, we have a continuation. Skip forward through 175 subsequent stabs to gather all the parts of the 176 continuation. Increment i, but keep st pointing at 177 current stab. */ 178 179 qcontinuing = string[qlen-1] == '\\'; 180 181 /* remove trailing \ */ 182 while (string[qlen-1] == '\\' && qlen > 0) 183 qlen--; 184 185 if (contdebug) 186 VG_(printf)("found extension string: \"%s\" " 187 "len=%d(%c) idx=%d buflen=%d\n", 188 string, qlen, string[qlen-1], qidx, qbuflen); 189 190 /* XXX this is silly. The si->strtab should have a way of 191 appending to the last added string... */ 192 if ((qidx + qlen) >= qbuflen) { 193 Char *n; 194 195 if (qbuflen == 0) 196 qbuflen = 16; 197 while ((qidx + qlen) >= qbuflen) 198 qbuflen *= 2; 199 n = ML_(dinfo_zalloc)("di.readstabs.rds.1", qbuflen); 200 VG_(memcpy)(n, qbuf, qidx); 201 202 if (qbuf != NULL) 203 ML_(dinfo_free)(qbuf); 204 qbuf = n; 205 } 206 207 VG_(memcpy)(&qbuf[qidx], string, qlen); 208 qidx += qlen; 209 if (contdebug) { 210 qbuf[qidx] = '\0'; 211 VG_(printf)("working buf=\"%s\"\n", qbuf); 212 } 213 214 i++; 215 if (i >= n_stab_entries) 216 break; 217 218 if (stab[i].n_un.n_strx) { 219 string = stabstr + stab[i].n_un.n_strx; 220 qlen = VG_(strlen)(string); 221 } else { 222 string = NULL; 223 qlen = 0; 224 } 225 } 226 227 if (qbuf != NULL) { 228 i--; /* overstepped */ 229 string = ML_(addStr)(di, qbuf, qidx); 230 ML_(dinfo_free)(qbuf); 231 if (contdebug) 232 VG_(printf)("made composite: \"%s\"\n", string); 233 } 234 } 235 236 switch(st->n_type) { 237 case N_UNDEF: 238 /* new string table base */ 239 if (next_stabstr != NULL) { 240 stabstr_sz -= next_stabstr - stabstr; 241 stabstr = next_stabstr; 242 if (stabstr_sz <= 0) { 243 VG_(printf)(" @@ bad stabstr size %d\n", stabstr_sz); 244 return; 245 } 246 } 247 next_stabstr = stabstr + st->n_value; 248 break; 249 250 case N_BINCL: { 251 break; 252 } 253 254 case N_EINCL: 255 break; 256 257 case N_EXCL: 258 break; 259 260 case N_SOL: /* sub-source (include) file */ 261 if (line.ovf != 0) 262 VG_(message)(Vg_UserMsg, 263 "Warning: file %s is very big (> 65535 lines) " 264 "Line numbers and annotation for this file might " 265 "be wrong. Sorry.\n", 266 file.name); 267 /* FALLTHROUGH */ 268 269 case N_SO: { /* new source file */ 270 UChar *nm = string; 271 UInt len = VG_(strlen)(nm); 272 Addr addr = func.start + st->n_value; 273 274 if (line.addr != 0) { 275 /* finish off previous line */ 276 ML_(addLineInfo)(di, file.name, NULL, line.addr, 277 addr, line.no + line.ovf * LINENO_OVERFLOW, i); 278 } 279 280 /* reset line state */ 281 line.ovf = 0; 282 line.addr = 0; 283 line.prev = 0; 284 line.no = 0; 285 286 if (len > 0 && nm[len-1] != '/') { 287 file.name = ML_(addStr)(di, nm, -1); 288 if (debug) 289 VG_(printf)("new source: %s\n", file.name); 290 } else if (len == 0) 291 file.name = ML_(addStr)(di, "?1\0", -1); 292 293 break; 294 } 295 296 case N_SLINE: { /* line info */ 297 Addr addr = func.start + st->n_value; 298 299 if (line.addr != 0) { 300 /* there was a previous */ 301 ML_(addLineInfo)(di, file.name, NULL, line.addr, 302 addr, line.no + line.ovf * LINENO_OVERFLOW, i); 303 } 304 305 line.addr = addr; 306 line.prev = line.no; 307 line.no = (Int)((UShort)st->n_desc); 308 309 if (line.prev > line.no + OVERFLOW_DIFFERENCE && file.same) { 310 VG_(message)(Vg_DebugMsg, 311 "Line number overflow detected (%d --> %d) in %s\n", 312 line.prev, line.no, file.name); 313 line.ovf++; 314 } 315 file.same = True; 316 317 /* This is pretty horrible. If this is the first line of 318 the function, then bind any unbound symbols to the arg 319 scope, since they're probably arguments. */ 320 if (line.first) { 321 line.first = False; 322 323 /* remember first line of function */ 324 if (func.start != 0) { 325 func.line = line.no; 326 } 327 } 328 break; 329 } 330 331 case N_FUN: { /* function start/end */ 332 Addr addr = 0; /* end address for prev line/scope */ 333 Bool newfunc = False; 334 335 /* if this the end of the function or we haven't 336 previously finished the previous function... */ 337 if (*string == '\0' || func.start != 0) { 338 /* end of function */ 339 newfunc = False; 340 line.first = False; 341 342 /* end line at end of function */ 343 addr = func.start + st->n_value; 344 345 /* now between functions */ 346 func.start = 0; 347 348 // XXXX DEAD POINT XXXX 349 } 350 351 if (*string != '\0') { 352 /* new function */ 353 newfunc = True; 354 line.first = True; 355 356 /* line ends at start of next function */ 357 addr = di->text_debug_bias + st->n_value; 358 359 func.start = addr; 360 } 361 362 if (line.addr) { 363 ML_(addLineInfo)(di, file.name, NULL, line.addr, 364 addr, line.no + line.ovf * LINENO_OVERFLOW, i); 365 line.addr = 0; 366 } 367 368 //DEAD POINT 369 //DEAD POINT 370 break; 371 } 372 373 case N_LBRAC: { 374 /* open new scope */ 375 // DEAD POINT 376 break; 377 } 378 379 case N_RBRAC: { 380 /* close scope */ 381 // DEAD POINT 382 break; 383 } 384 385 case N_GSYM: /* global variable */ 386 case N_STSYM: /* static in data segment */ 387 case N_LCSYM: /* static in bss segment */ 388 case N_PSYM: /* function parameter */ 389 case N_LSYM: /* stack variable */ 390 case N_RSYM: /* register variable */ 391 break; 392 } 393 } 394 } 395 396 #endif // defined(VGO_linux) || defined(VGO_darwin) 397 398 /*--------------------------------------------------------------------*/ 399 /*--- end ---*/ 400 /*--------------------------------------------------------------------*/ 401