symstabs.c (8399B)
1 #include <u.h> 2 #include <libc.h> 3 #include <mach.h> 4 #include "stabs.h" 5 6 static int 7 strcmpcolon(char *a, char *bcolon) 8 { 9 int i, len; 10 char *p; 11 12 p = strchr(bcolon, ':'); 13 if(p == nil) 14 return strcmp(a, bcolon); 15 len = p-bcolon; 16 i = strncmp(a, bcolon, len); 17 if(i) 18 return i; 19 if(a[len] == 0) 20 return 0; 21 return 1; 22 } 23 24 static int 25 stabcvtsym(StabSym *stab, Symbol *sym, char *dir, char *file, int i) 26 { 27 char *p; 28 29 /* 30 * Zero out the : to avoid allocating a new name string. 31 * The type info can be found by looking past the NUL. 32 * This is going to get us in trouble... 33 */ 34 if((p = strchr(stab->name, ':')) != nil) 35 *p++ = 0; 36 else 37 p = stab->name+strlen(stab->name)+1; 38 39 sym->name = stab->name; 40 sym->u.stabs.dir = dir; 41 sym->u.stabs.file = file; 42 sym->u.stabs.i = i; 43 switch(stab->type){ 44 default: 45 return -1; 46 case N_FUN: 47 sym->class = CTEXT; 48 switch(*p){ 49 default: 50 return -1; 51 case 'F': /* global function */ 52 sym->type = 'T'; 53 break; 54 case 'Q': /* static procedure */ 55 case 'f': /* static function */ 56 case 'I': /* nested procedure */ 57 case 'J': /* nested function */ 58 sym->type = 't'; 59 break; 60 } 61 sym->loc.type = LADDR; 62 sym->loc.addr = stab->value; 63 break; 64 case N_GSYM: 65 case N_PSYM: 66 case N_LSYM: 67 case N_LCSYM: 68 sym->class = CDATA; 69 sym->loc.type = LADDR; 70 sym->loc.addr = stab->value; 71 switch(*p){ 72 default: 73 return -1; 74 case 'S': /* file-scope static variable */ 75 sym->type = 'd'; 76 break; 77 case 'G': /* global variable */ 78 sym->type = 'D'; 79 sym->loc.type = LNONE; 80 break; 81 case 'r': /* register variable */ 82 sym->class = CAUTO; 83 sym->type = 'a'; 84 sym->loc.type = LREG; 85 sym->loc.reg = "XXX"; 86 break; 87 case 's': /* local variable */ 88 sym->class = CAUTO; 89 sym->type = 'a'; 90 sym->loc.type = LOFFSET; 91 sym->loc.offset = stab->value; 92 sym->loc.reg = "XXX"; 93 break; 94 case 'a': /* by reference */ 95 case 'D': /* f.p. parameter */ 96 case 'i': /* register parameter */ 97 case 'p': /* "normal" parameter */ 98 case 'P': /* register parameter */ 99 case 'v': /* by reference */ 100 case 'X': /* function return variable */ 101 sym->class = CPARAM; 102 sym->type = 'p'; 103 if(*p == 'i'){ 104 sym->loc.type = LREG; 105 sym->loc.reg = "XXX"; 106 }else{ 107 sym->loc.type = LOFFSET; 108 sym->loc.offset = stab->value; 109 sym->loc.reg = "XXX"; 110 } 111 break; 112 } 113 break; 114 } 115 return 0; 116 } 117 118 static int 119 stabssyminit(Fhdr *fp) 120 { 121 int i; 122 char *dir, *file; 123 Stab *stabs; 124 StabSym sym, lastfun; 125 Symbol s, *fun; 126 char **inc, **xinc; 127 int ninc, minc; 128 int locals, autos, params; 129 130 stabs = &fp->stabs; 131 if(stabs == nil){ 132 werrstr("no stabs info"); 133 return -1; 134 } 135 136 dir = nil; 137 file = nil; 138 inc = nil; 139 fun = nil; 140 ninc = 0; 141 minc = 0; 142 locals = 0; 143 params = 0; 144 autos = 0; 145 memset(&lastfun, 0, sizeof lastfun); 146 for(i=0; stabsym(stabs, i, &sym)>=0; i++){ 147 switch(sym.type){ 148 case N_SO: 149 if(sym.name == nil || *sym.name == 0){ 150 file = nil; 151 break; 152 } 153 if(sym.name[strlen(sym.name)-1] == '/') 154 dir = sym.name; 155 else 156 file = sym.name; 157 break; 158 case N_BINCL: 159 if(ninc >= minc){ 160 xinc = realloc(inc, (ninc+32)*sizeof(inc[0])); 161 if(xinc){ 162 memset(xinc+ninc, 0, 32*sizeof(inc[0])); 163 inc = xinc; 164 } 165 ninc += 32; 166 } 167 if(ninc < minc) 168 inc[ninc] = sym.name; 169 ninc++; 170 break; 171 case N_EINCL: 172 if(ninc > 0) 173 ninc--; 174 break; 175 case N_EXCL: 176 /* condensed include - same effect as previous BINCL/EINCL pair */ 177 break; 178 case N_GSYM: /* global variable */ 179 /* only includes type, so useless for now */ 180 break; 181 case N_FUN: 182 if(sym.name == nil){ 183 /* marks end of function */ 184 if(fun){ 185 fun->hiloc.type = LADDR; 186 fun->hiloc.addr = fun->loc.addr + sym.value; 187 } 188 break; 189 } 190 if(fun && lastfun.value==sym.value && lastfun.name==sym.name){ 191 fun->u.stabs.locals = i; 192 break; 193 } 194 /* create new symbol, add it */ 195 lastfun = sym; 196 fun = nil; 197 if(stabcvtsym(&sym, &s, dir, file, i) < 0) 198 continue; 199 if((fun = _addsym(fp, &s)) == nil) 200 goto err; 201 locals = 0; 202 params = 0; 203 autos = 0; 204 break; 205 case N_PSYM: 206 case N_LSYM: 207 case N_LCSYM: 208 if(fun){ 209 if(fun->u.stabs.frameptr == -1){ 210 /* 211 * Try to distinguish functions with a real frame pointer 212 * from functions with a virtual frame pointer, based on 213 * whether the first parameter is in the right location and 214 * whether the autos have negative offsets. 215 * 216 * This heuristic works most of the time. On the 386, we 217 * cannot distinguish between a v. function with no autos 218 * but a frame of size 4 and a f.p. function with no autos and 219 * no frame. Anything else we'll get right. 220 * 221 * Another way to go about this would be to have 222 * mach-specific functions to inspect the function 223 * prologues when we're not sure. What we have 224 * already should be enough, though. 225 */ 226 if(params==0 && sym.type == N_PSYM){ 227 if(sym.value != 8 && sym.value >= 4){ 228 /* XXX 386 specific, but let's find another system before generalizing */ 229 fun->u.stabs.frameptr = 0; 230 fun->u.stabs.framesize = sym.value - 4; 231 } 232 }else if(sym.type == N_LSYM){ 233 if((int32)sym.value >= 0){ 234 fun->u.stabs.frameptr = 0; 235 if(params) 236 fun->u.stabs.framesize = 8 - 4; 237 }else 238 fun->u.stabs.frameptr = 1; 239 } 240 } 241 if(sym.type == N_PSYM) 242 params++; 243 if(sym.type == N_LSYM) 244 autos++; 245 } 246 break; 247 248 case N_STSYM: /* static file-scope variable */ 249 /* create new symbol, add it */ 250 if(stabcvtsym(&sym, &s, dir, file, i) < 0) 251 continue; 252 if(_addsym(fp, &s) == nil) 253 goto err; 254 break; 255 } 256 } 257 USED(locals); 258 free(inc); 259 return 0; 260 261 err: 262 free(inc); 263 return -1; 264 } 265 266 static int 267 stabspc2file(Fhdr *fhdr, u64int pc, char *buf, uint nbuf, ulong *pline) 268 { 269 int i; 270 Symbol *s; 271 StabSym ss; 272 ulong line, basepc; 273 Loc l; 274 275 l.type = LADDR; 276 l.addr = pc; 277 if((s = ffindsym(fhdr, l, CTEXT)) == nil 278 || stabsym(&fhdr->stabs, s->u.stabs.i, &ss) < 0) 279 return -1; 280 281 line = ss.desc; 282 basepc = ss.value; 283 for(i=s->u.stabs.i+1; stabsym(&fhdr->stabs, i, &ss) >= 0; i++){ 284 if(ss.type == N_FUN && ss.name == nil) 285 break; 286 if(ss.type == N_SLINE){ 287 if(basepc+ss.value > pc) 288 break; 289 else 290 line = ss.desc; 291 } 292 } 293 *pline = line; 294 if(s->u.stabs.dir) 295 snprint(buf, nbuf, "%s%s", s->u.stabs.dir, s->u.stabs.file); 296 else 297 snprint(buf, nbuf, "%s", s->u.stabs.file); 298 return 0; 299 } 300 301 static int 302 stabsline2pc(Fhdr *fhdr, u64int startpc, ulong line, u64int *pc) 303 { 304 int i, trigger; 305 Symbol *s; 306 StabSym ss; 307 ulong basepc; 308 Loc l; 309 310 l.type = LADDR; 311 l.addr = startpc; 312 if((s = ffindsym(fhdr, l, CTEXT)) == nil 313 || stabsym(&fhdr->stabs, s->u.stabs.i, &ss) < 0) 314 return -1; 315 316 trigger = 0; 317 line = ss.desc; 318 basepc = ss.value; 319 for(i=s->u.stabs.i+1; stabsym(&fhdr->stabs, i, &ss) >= 0; i++){ 320 if(ss.type == N_FUN) 321 basepc = ss.value; 322 if(ss.type == N_SLINE){ 323 if(basepc+ss.value >= startpc) 324 trigger = 1; 325 if(trigger && ss.desc >= line){ 326 *pc = basepc+ss.value; 327 return 0; 328 } 329 } 330 } 331 return -1; 332 } 333 334 static int 335 stabslenum(Fhdr *fhdr, Symbol *p, char *name, uint j, Loc l, Symbol *s) 336 { 337 int i; 338 StabSym ss; 339 340 for(i=p->u.stabs.locals; stabsym(&fhdr->stabs, i, &ss)>=0; i++){ 341 if(ss.type == N_FUN && ss.name == nil) 342 break; 343 switch(ss.type){ 344 case N_PSYM: 345 case N_LSYM: 346 case N_LCSYM: 347 if(name){ 348 if(strcmpcolon(name, ss.name) != 0) 349 break; 350 }else if(l.type){ 351 /* wait for now */ 352 }else{ 353 if(j-- > 0) 354 break; 355 } 356 if(stabcvtsym(&ss, s, p->u.stabs.dir, p->u.stabs.file, i) < 0) 357 return -1; 358 if(s->loc.type == LOFFSET){ 359 if(p->u.stabs.frameptr == 0) 360 s->loc.reg = mach->sp; 361 else 362 s->loc.reg = mach->fp; 363 } 364 if(l.type && loccmp(&l, &s->loc) != 0) 365 break; 366 return 0; 367 } 368 } 369 return -1; 370 } 371 372 static Loc zl; 373 374 static int 375 stabslookuplsym(Fhdr *fhdr, Symbol *p, char *name, Symbol *s) 376 { 377 return stabslenum(fhdr, p, name, 0, zl, s); 378 } 379 380 static int 381 stabsindexlsym(Fhdr *fhdr, Symbol *p, uint i, Symbol *s) 382 { 383 return stabslenum(fhdr, p, nil, i, zl, s); 384 } 385 386 static int 387 stabsfindlsym(Fhdr *fhdr, Symbol *p, Loc l, Symbol *s) 388 { 389 return stabslenum(fhdr, p, nil, 0, l, s); 390 } 391 392 int 393 symstabs(Fhdr *fp) 394 { 395 if(stabssyminit(fp) < 0) 396 return -1; 397 fp->pc2file = stabspc2file; 398 fp->line2pc = stabsline2pc; 399 fp->lookuplsym = stabslookuplsym; 400 fp->indexlsym = stabsindexlsym; 401 fp->findlsym = stabsfindlsym; 402 return 0; 403 }