ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

dwarfpc.c
Go to the documentation of this file.
00001 /*
00002  * Dwarf pc to source line conversion.
00003  * 
00004  * Maybe should do the reverse here, but what should the interface look like?
00005  * One possibility is to use the Plan 9 line2addr interface:
00006  *
00007  *  long line2addr(ulong line, ulong basepc)
00008  *
00009  * which returns the smallest pc > basepc with line number line (ignoring file name).
00010  *
00011  * The encoding may be small, but it sure isn't simple!
00012  */
00013 
00014 #include <precomp.h>
00015 
00016 #define NDEBUG
00017 #include <debug.h>
00018 #define trace 0
00019 
00020 enum
00021 {
00022     Isstmt = 1<<0,
00023     BasicDwarfBlock = 1<<1,
00024     EndSequence = 1<<2,
00025     PrologueEnd = 1<<3,
00026     EpilogueBegin = 1<<4
00027 };
00028 
00029 typedef struct State State;
00030 struct State
00031 {
00032     ulong addr;
00033     ulong file;
00034     ulong line;
00035     ulong column;
00036     ulong flags;
00037     ulong isa;
00038 };
00039 
00040 int
00041 dwarfpctoline(Dwarf *d, DwarfSym *proc, ulong pc, char **file, char **function, ulong *line)
00042 {
00043     char *cdir;
00044     uchar *prog, *opcount, *end, *dirs;
00045     ulong off, unit, len, vers, x, start, lastline;
00046     int i, first, firstline, op, a, l, quantum, isstmt, linebase, linerange, opcodebase, nf;
00047     char *files, *s;
00048     DwarfBuf b;
00049     DwarfSym sym;
00050     State emit, cur, reset;
00051     char **f, **newf;
00052 
00053     f = nil;
00054     memset(proc, 0, sizeof(*proc));
00055 
00056     int runit = dwarfaddrtounit(d, pc, &unit);
00057     if (runit < 0)
00058         return -1;
00059     int rtag = dwarflookuptag(d, unit, TagCompileUnit, &sym);
00060     if (rtag < 0)
00061         return -1;
00062 
00063     if(!sym.attrs.have.stmtlist){
00064         werrstr("no line mapping information for 0x%x", pc);
00065         return -1;
00066     }
00067     off = sym.attrs.stmtlist;
00068     if(off >= d->line.len){
00069         werrstr("bad stmtlist");
00070         goto bad;
00071     }
00072 
00073     if(trace) werrstr("unit 0x%x stmtlist 0x%x", unit, sym.attrs.stmtlist);
00074 
00075     memset(&b, 0, sizeof b);
00076     b.d = d;
00077     b.p = d->line.data + off;
00078     b.ep = b.p + d->line.len;
00079     b.addrsize = sym.b.addrsize;    /* should i get this from somewhere else? */
00080 
00081     len = dwarfget4(&b);
00082     if(b.p==nil || b.p+len > b.ep || b.p+len < b.p){
00083         werrstr("bad len");
00084         goto bad;
00085     }
00086 
00087     b.ep = b.p+len;
00088     vers = dwarfget2(&b);
00089     if(vers != 2){
00090         werrstr("bad dwarf version 0x%x", vers);
00091         return -1;
00092     }
00093 
00094     len = dwarfget4(&b);
00095     if(b.p==nil || b.p+len > b.ep || b.p+len < b.p){
00096         werrstr("another bad len");
00097         goto bad;
00098     }
00099     prog = b.p+len;
00100 
00101     quantum = dwarfget1(&b);
00102     isstmt = dwarfget1(&b);
00103     linebase = (schar)dwarfget1(&b);
00104     linerange = (schar)dwarfget1(&b);
00105     opcodebase = dwarfget1(&b);
00106 
00107     opcount = b.p-1;
00108     dwarfgetnref(&b, opcodebase-1);
00109     if(b.p == nil){
00110         werrstr("bad opcode chart");
00111         goto bad;
00112     }
00113 
00114     /* just skip the files and dirs for now; we'll come back */
00115     dirs = b.p;
00116     while (b.p && *b.p)
00117         dwarfgetstring(&b);
00118     dwarfget1(&b);
00119 
00120     files = (char*)b.p;
00121     while(b.p!=nil && *b.p!=0){
00122         dwarfgetstring(&b);
00123         dwarfget128(&b);
00124         dwarfget128(&b);
00125         dwarfget128(&b);
00126     }
00127     dwarfget1(&b);
00128 
00129     /* move on to the program */
00130     if(b.p == nil || b.p > prog){
00131         werrstr("bad header");
00132         goto bad;
00133     }
00134     b.p = prog;
00135 
00136     reset.addr = 0;
00137     reset.file = 1;
00138     reset.line = 1;
00139     reset.column = 0;
00140     reset.flags = isstmt ? Isstmt : 0;
00141     reset.isa = 0;
00142 
00143     cur = reset;
00144     emit = reset;
00145     nf = 0;
00146     start = 0;
00147     if(trace) werrstr("program @ %lu ... %.*H opbase = %d", b.p - d->line.data, b.ep-b.p, b.p, opcodebase);
00148     first = 1;
00149     while(b.p != nil){
00150         firstline = 0;
00151         op = dwarfget1(&b);
00152         if(trace) werrstr("\tline %lu, addr 0x%x, op %d %.10H", cur.line, cur.addr, op, b.p);
00153         if(op >= opcodebase){
00154             a = (op - opcodebase) / linerange;
00155             l = (op - opcodebase) % linerange + linebase;
00156             cur.line += l;
00157             cur.addr += a * quantum;
00158             if(trace) werrstr(" +%d,%d", a, l);
00159         emit:
00160             if(first){
00161                 if(cur.addr > pc){
00162                     werrstr("found wrong line mapping 0x%x for pc 0x%x", cur.addr, pc);
00163                     /* This is an overzealous check.  gcc can produce discontiguous ranges
00164                        and reorder statements, so it's possible for a future line to start
00165                        ahead of pc and still find a matching one. */
00166                     /*goto out;*/
00167                     firstline = 1;
00168                 }
00169                 first = 0;
00170                 start = cur.addr;
00171             }
00172             if(cur.addr > pc && !firstline)
00173                 break;
00174             if(b.p == nil){
00175                 werrstr("buffer underflow in line mapping");
00176                 goto out;
00177             }
00178             emit = cur;
00179             if(emit.flags & EndSequence){
00180                 werrstr("found wrong line mapping 0x%x-0x%x for pc 0x%x", start, cur.addr, pc);
00181                 goto out;
00182             }
00183             cur.flags &= ~(BasicDwarfBlock|PrologueEnd|EpilogueBegin);
00184         }else{
00185             switch(op){
00186             case 0: /* extended op code */
00187                 if(trace) werrstr(" ext");
00188                 len = dwarfget128(&b);
00189                 end = b.p+len;
00190                 if(b.p == nil || end > b.ep || end < b.p || len < 1)
00191                     goto bad;
00192                 switch(dwarfget1(&b)){
00193                 case 1: /* end sequence */
00194                     if(trace) werrstr(" end");
00195                     cur.flags |= EndSequence;
00196                     goto emit;
00197                 case 2: /* set address */
00198                     cur.addr = dwarfgetaddr(&b);
00199                     if(trace) werrstr(" set pc 0x%x", cur.addr);
00200                     break;
00201                 case 3: /* define file */
00202                     newf = malloc(nf+1*sizeof(f[0]));
00203                     if (newf)
00204                         RtlMoveMemory(newf, f, nf*sizeof(f[0]));
00205                     if(newf == nil)
00206                         goto out;
00207                     free(f);
00208                     f = newf;
00209                     f[nf++] = s = dwarfgetstring(&b);
00210                     DPRINT1("str %s", s);
00211                     dwarfget128(&b);
00212                     dwarfget128(&b);
00213                     dwarfget128(&b);
00214                     if(trace) werrstr(" def file %s", s);
00215                     break;
00216                 }
00217                 if(b.p == nil || b.p > end)
00218                     goto bad;
00219                 b.p = end;
00220                 break;
00221             case 1: /* emit */
00222                 if(trace) werrstr(" emit");
00223                 goto emit;
00224             case 2: /* advance pc */
00225                 a = dwarfget128(&b);
00226                 if(trace) werrstr(" advance pc + %lu", a*quantum);
00227                 cur.addr += a * quantum;
00228                 break;
00229             case 3: /* advance line */
00230                 l = dwarfget128s(&b);
00231                 if(trace) werrstr(" advance line + %ld", l);
00232                 cur.line += l;
00233                 break;
00234             case 4: /* set file */
00235                 if(trace) werrstr(" set file");
00236                 cur.file = dwarfget128s(&b);
00237                 break;
00238             case 5: /* set column */
00239                 if(trace) werrstr(" set column");
00240                 cur.column = dwarfget128(&b);
00241                 break;
00242             case 6: /* negate stmt */
00243                 if(trace) werrstr(" negate stmt");
00244                 cur.flags ^= Isstmt;
00245                 break;
00246             case 7: /* set basic block */
00247                 if(trace) werrstr(" set basic block");
00248                 cur.flags |= BasicDwarfBlock;
00249                 break;
00250             case 8: /* const add pc */
00251                 a = (255 - opcodebase) / linerange * quantum;
00252                 if(trace) werrstr(" const add pc + %d", a);
00253                 cur.addr += a;
00254                 break;
00255             case 9: /* fixed advance pc */
00256                 a = dwarfget2(&b);
00257                 if(trace) werrstr(" fixed advance pc + %d", a);
00258                 cur.addr += a;
00259                 break;
00260             case 10:    /* set prologue end */
00261                 if(trace) werrstr(" set prologue end");
00262                 cur.flags |= PrologueEnd;
00263                 break;
00264             case 11:    /* set epilogue begin */
00265                 if(trace) werrstr(" set epilogue begin");
00266                 cur.flags |= EpilogueBegin;
00267                 break;
00268             case 12:    /* set isa */
00269                 if(trace) werrstr(" set isa");
00270                 cur.isa = dwarfget128(&b);
00271                 break;
00272             default:    /* something new - skip it */
00273                 if(trace) werrstr(" unknown %d", opcount[op]);
00274                 for(i=0; i<opcount[op]; i++)
00275                     dwarfget128(&b);
00276                 break;
00277             }
00278         }
00279     }
00280     if(b.p == nil)
00281         goto bad;
00282 
00283     /* finally!  the data we seek is in "emit" */
00284 
00285     if(emit.file == 0){
00286         werrstr("invalid file index in mapping data");
00287         goto out;
00288     }
00289     if(line)
00290         *line = emit.line;
00291 
00292     /* skip over first emit.file-2 guys */
00293     b.p = (uchar*)files;
00294     for(i=emit.file-1; i > 0 && b.p!=nil && *b.p!=0; i--){
00295         dwarfgetstring(&b);
00296         dwarfget128(&b);
00297         dwarfget128(&b);
00298         dwarfget128(&b);
00299     }
00300     if(b.p == nil){
00301         werrstr("problem parsing file data second time (cannot happen)");
00302         goto bad;
00303     }
00304     if(*b.p == 0){
00305         if(i >= nf){
00306             werrstr("bad file index in mapping data");
00307             goto bad;
00308         }
00309         b.p = (uchar*)f[i];
00310     }
00311     s = dwarfgetstring(&b);
00312     *file = s;
00313     i = dwarfget128(&b);        /* directory */
00314     x = dwarfget128(&b);
00315     x = dwarfget128(&b);
00316 
00317     /* fetch dir name */
00318     cdir = sym.attrs.have.compdir ? sym.attrs.compdir : 0;
00319 
00320     char *dwarfdir;
00321     dwarfdir = nil;
00322     b.p = dirs;
00323     for (x = 1; b.p && *b.p; x++) {
00324         dwarfdir = dwarfgetstring(&b);
00325         if (x == i) break;
00326     }
00327 
00328     if (!cdir && dwarfdir)
00329         cdir = dwarfdir;
00330     
00331     char *filefull = malloc(strlen(cdir) + strlen(*file) + 2);
00332     strcpy(filefull, cdir);
00333     strcat(filefull, "/");
00334     strcat(filefull, *file);
00335     *file = filefull;
00336     
00337     *function = nil;
00338     lastline = 0;
00339     
00340     runit = dwarfaddrtounit(d, pc, &unit);
00341     if (runit == 0) {
00342         DwarfSym compunit = { };
00343         int renum = dwarfenumunit(d, unit, &compunit);
00344         if (renum < 0)
00345             return -1;
00346         renum = dwarfnextsymat(d, &compunit, proc);
00347         while (renum == 0) {
00348             if (proc->attrs.tag == TagSubprogram && 
00349                 proc->attrs.have.name)
00350             {
00351                 if (proc->attrs.lowpc <= pc && proc->attrs.highpc > pc) {
00352                     *function = malloc(strlen(proc->attrs.name)+1);
00353                     strcpy(*function, proc->attrs.name);
00354                     goto done;
00355                 }
00356             }
00357             renum = dwarfnextsym(d, proc);
00358         }
00359     }
00360 
00361     // Next search by declaration
00362     runit = dwarfaddrtounit(d, pc, &unit);
00363     if (runit == 0) {
00364         DwarfSym compunit = { };
00365         int renum = dwarfenumunit(d, unit, &compunit);
00366         if (renum < 0)
00367             return -1;
00368         renum = dwarfnextsymat(d, &compunit, proc);
00369         while (renum == 0) {
00370             if (proc->attrs.tag == TagSubprogram && 
00371                 proc->attrs.have.name &&
00372                 proc->attrs.declfile == emit.file)
00373             {
00374                 if (proc->attrs.declline <= *line &&
00375                     proc->attrs.declline > lastline) {
00376                     free(*function);
00377                     *function = malloc(strlen(proc->attrs.name)+1);
00378                     strcpy(*function, proc->attrs.name);
00379                     goto done;
00380                 }
00381                 lastline = proc->attrs.declline;
00382             }
00383             renum = dwarfnextsym(d, proc);
00384         }
00385     }
00386 
00387     /* free at last, free at last */
00388 done:
00389     free(f);
00390     return 0;
00391 bad:
00392     werrstr("corrupted line mapping for 0x%x", pc);
00393 out:
00394     free(f);
00395     return -1;
00396 }
00397 
00398 VOID RosSymFreeInfo(PROSSYM_LINEINFO LineInfo)
00399 {
00400     int i;
00401     free(LineInfo->FileName);
00402     LineInfo->FileName = NULL;
00403     free(LineInfo->FunctionName);
00404     LineInfo->FunctionName = NULL;
00405     for (i = 0; i < sizeof(LineInfo->Parameters)/sizeof(LineInfo->Parameters[0]); i++)
00406         free(LineInfo->Parameters[i].ValueName);
00407 }

Generated on Sun May 27 2012 04:36:17 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.