Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygendwarfpc.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
1.7.6.1
|