URI:
       tsymstabs.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tsymstabs.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 }