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 #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
1.7.6.1
|