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

Generated on Fri May 25 2012 04:34:47 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.