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