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