Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygendwarfcfa.c
Go to the documentation of this file.
00001 /* 00002 * Dwarf call frame unwinding. 00003 * 00004 * The call frame unwinding values are encoded using a state machine 00005 * like the pc<->line mapping, but it's a different machine. 00006 * The expressions to generate the old values are similar in function to the 00007 * ``dwarf expressions'' used for locations in the code, but of course not 00008 * the same encoding. 00009 */ 00010 00011 #include <precomp.h> 00012 00013 #define NDEBUG 00014 #include <debug.h> 00015 00016 #define trace 1 00017 00018 typedef struct State State; 00019 struct State 00020 { 00021 ulong loc; 00022 ulong endloc; 00023 ulong iquantum; 00024 ulong dquantum; 00025 char *augmentation; 00026 int version; 00027 ulong rareg; 00028 DwarfBuf init; 00029 DwarfExpr *cfa; 00030 DwarfExpr *ra; 00031 DwarfExpr *r; 00032 DwarfExpr *initr; 00033 int nr; 00034 DwarfExpr **stack; 00035 int nstack; 00036 }; 00037 00038 static int findfde(Dwarf*, ulong, State*, DwarfBuf*); 00039 static int dexec(DwarfBuf*, State*, int); 00040 00041 int 00042 dwarfunwind(Dwarf *d, ulong pc, DwarfExpr *cfa, DwarfExpr *ra, DwarfExpr *r, int nr) 00043 { 00044 int i, ret; 00045 DwarfBuf fde, b; 00046 DwarfExpr *initr; 00047 State s; 00048 00049 initr = mallocz(nr*sizeof(initr[0]), 1); 00050 if(initr == 0) 00051 return -1; 00052 00053 memset(&s, 0, sizeof s); 00054 s.loc = 0; 00055 s.cfa = cfa; 00056 s.ra = ra; 00057 s.r = r; 00058 s.nr = nr; 00059 00060 if(findfde(d, pc, &s, &fde) < 0){ 00061 free(initr); 00062 return -1; 00063 } 00064 00065 memset(r, 0, nr*sizeof(r[0])); 00066 for(i=0; i<nr; i++) 00067 r[i].type = RuleSame; 00068 if(trace) werrstr("s.init %p-%p, fde %p-%p", s.init.p, s.init.ep, fde.p, fde.ep); 00069 b = s.init; 00070 if(dexec(&b, &s, 0) < 0) 00071 goto err; 00072 00073 s.initr = initr; 00074 memmove(initr, r, nr*sizeof(initr[0])); 00075 00076 if(trace) werrstr("s.loc 0x%lx pc 0x%lx", s.loc, pc); 00077 while(s.loc < pc){ 00078 if(trace) werrstr("s.loc 0x%lx pc 0x%lx", s.loc, pc); 00079 if(dexec(&fde, &s, 1) < 0) 00080 goto err; 00081 } 00082 *ra = s.r[s.rareg]; 00083 00084 ret = 0; 00085 goto out; 00086 00087 err: 00088 ret = -1; 00089 out: 00090 free(initr); 00091 for(i=0; i<s.nstack; i++) 00092 free(s.stack[i]); 00093 free(s.stack); 00094 return ret; 00095 } 00096 00097 /* 00098 * XXX This turns out to be much more expensive than the actual 00099 * running of the machine in dexec. It probably makes sense to 00100 * cache the last 10 or so fde's we've found, since stack traces 00101 * will keep asking for the same info over and over. 00102 */ 00103 static int 00104 findfde(Dwarf *d, ulong pc, State *s, DwarfBuf *fde) 00105 { 00106 static int nbad; 00107 char *aug; 00108 uchar *next; 00109 int i, vers; 00110 ulong len, id, base, size; 00111 DwarfBuf b; 00112 00113 if(d->frame.data == nil){ 00114 werrstr("no frame debugging information"); 00115 return -1; 00116 } 00117 b.d = d; 00118 b.p = d->frame.data; 00119 b.ep = b.p + d->frame.len; 00120 b.addrsize = d->addrsize; 00121 if(b.addrsize == 0) 00122 b.addrsize = 4; /* where should i find this? */ 00123 00124 for(; b.p < b.ep; b.p = next){ 00125 if((i = (b.p - d->frame.data) % b.addrsize)) 00126 b.p += b.addrsize - i; 00127 len = dwarfget4(&b); 00128 if(len > b.ep-b.p){ 00129 werrstr("bad length in cie/fde header"); 00130 return -1; 00131 } 00132 next = b.p+len; 00133 id = dwarfget4(&b); 00134 if(id == 0xFFFFFFFF){ /* CIE */ 00135 vers = dwarfget1(&b); 00136 if (trace) werrstr("CIE len %x id %x vers %x", len, id, vers); 00137 if(vers != 1 && vers != 2 && vers != 3){ 00138 if(++nbad == 1) 00139 werrstr("unknown cie version %d (wanted 1-3)", vers); 00140 continue; 00141 } 00142 aug = dwarfgetstring(&b); 00143 if(aug && *aug){ 00144 if(++nbad == 1) 00145 werrstr("unknown augmentation: %s", aug); 00146 continue; 00147 } 00148 s->iquantum = dwarfget128(&b); 00149 s->dquantum = dwarfget128s(&b); 00150 s->rareg = dwarfget128(&b); 00151 if(s->rareg > s->nr){ 00152 werrstr("return address is register %d but only have %d registers", 00153 s->rareg, s->nr); 00154 return -1; 00155 } 00156 s->init.p = b.p; 00157 s->init.ep = next; 00158 }else{ /* FDE */ 00159 base = dwarfgetaddr(&b); 00160 size = dwarfgetaddr(&b); 00161 if (trace) werrstr("FDE: base %x-%x (want pc %x)", base, base+size, pc); 00162 fde->p = b.p; 00163 fde->ep = next; 00164 s->loc = base; 00165 s->endloc = base+size; 00166 if(base <= pc && pc < base+size) 00167 return 0; 00168 } 00169 } 00170 werrstr("cannot find call frame information for pc 0x%lx", pc); 00171 return -1; 00172 00173 } 00174 00175 static int 00176 checkreg(State *s, long r) 00177 { 00178 if(r < 0 || r >= s->nr){ 00179 werrstr("bad register number 0x%lx", r); 00180 return -1; 00181 } 00182 return 0; 00183 } 00184 00185 static int 00186 dexec(DwarfBuf *b, State *s, int locstop) 00187 { 00188 int c; 00189 long arg1, arg2; 00190 DwarfExpr *e; 00191 00192 for(;;){ 00193 if(b->p == b->ep){ 00194 if(s->initr) 00195 s->loc = s->endloc; 00196 werrstr("end dexec"); 00197 return 0; 00198 } 00199 c = dwarfget1(b); 00200 if(b->p == nil){ 00201 werrstr("ran out of instructions during cfa program"); 00202 if(trace) werrstr("%r"); 00203 return -1; 00204 } 00205 if(trace) werrstr("+ loc=0x%x op 0x%x ", s->loc, c); 00206 switch(c>>6){ 00207 case 1: /* advance location */ 00208 arg1 = c&0x3F; 00209 advance: 00210 if(trace) werrstr("loc += %ld", arg1*s->iquantum); 00211 s->loc += arg1 * s->iquantum; 00212 if(locstop) 00213 return 0; 00214 continue; 00215 00216 case 2: /* offset rule */ 00217 arg1 = c&0x3F; 00218 arg2 = dwarfget128(b); 00219 offset: 00220 if(trace) werrstr("r%ld += %ld", arg1, arg2*s->dquantum); 00221 if(checkreg(s, arg1) < 0) 00222 return -1; 00223 s->r[arg1].type = RuleCfaOffset; 00224 s->r[arg1].offset = arg2 * s->dquantum; 00225 continue; 00226 00227 case 3: /* restore initial setting */ 00228 arg1 = c&0x3F; 00229 restore: 00230 if(trace) werrstr("r%ld = init", arg1); 00231 if(checkreg(s, arg1) < 0) 00232 return -1; 00233 s->r[arg1] = s->initr[arg1]; 00234 continue; 00235 } 00236 00237 switch(c){ 00238 case 0: /* nop */ 00239 if(trace) werrstr("nop"); 00240 continue; 00241 00242 case 0x01: /* set location */ 00243 s->loc = dwarfgetaddr(b); 00244 if(trace) werrstr("loc = 0x%lx", s->loc); 00245 if(locstop) 00246 return 0; 00247 continue; 00248 00249 case 0x02: /* advance loc1 */ 00250 arg1 = dwarfget1(b); 00251 goto advance; 00252 00253 case 0x03: /* advance loc2 */ 00254 arg1 = dwarfget2(b); 00255 goto advance; 00256 00257 case 0x04: /* advance loc4 */ 00258 arg1 = dwarfget4(b); 00259 goto advance; 00260 00261 case 0x05: /* offset extended */ 00262 arg1 = dwarfget128(b); 00263 arg2 = dwarfget128(b); 00264 goto offset; 00265 00266 case 0x06: /* restore extended */ 00267 arg1 = dwarfget128(b); 00268 goto restore; 00269 00270 case 0x07: /* undefined */ 00271 arg1 = dwarfget128(b); 00272 if(trace) werrstr("r%ld = undef", arg1); 00273 if(checkreg(s, arg1) < 0) 00274 return -1; 00275 s->r[arg1].type = RuleUndef; 00276 continue; 00277 00278 case 0x08: /* same value */ 00279 arg1 = dwarfget128(b); 00280 if(trace) werrstr("r%ld = same", arg1); 00281 if(checkreg(s, arg1) < 0) 00282 return -1; 00283 s->r[arg1].type = RuleSame; 00284 continue; 00285 00286 case 0x09: /* register */ 00287 arg1 = dwarfget128(b); 00288 arg2 = dwarfget128(b); 00289 if(trace) werrstr("r%ld = r%ld", arg1, arg2); 00290 if(checkreg(s, arg1) < 0 || checkreg(s, arg2) < 0) 00291 return -1; 00292 s->r[arg1].type = RuleRegister; 00293 s->r[arg1].reg = arg2; 00294 continue; 00295 00296 case 0x0A: /* remember state */ 00297 e = malloc(s->nr*sizeof(e[0])); 00298 if(trace) werrstr("push"); 00299 if(e == nil) 00300 return -1; 00301 void *newstack = malloc(s->nstack*sizeof(s->stack[0])); 00302 RtlMoveMemory(newstack, s->stack, s->nstack*sizeof(s->stack[0])); 00303 if (newstack) { 00304 free(s->stack); 00305 s->stack = newstack; 00306 } else { 00307 free(e); 00308 return -1; 00309 } 00310 if(b->p == nil){ 00311 free(e); 00312 return -1; 00313 } 00314 s->stack[s->nstack++] = e; 00315 memmove(e, s->r, s->nr*sizeof(e[0])); 00316 continue; 00317 00318 case 0x0B: /* restore state */ 00319 if(trace) werrstr("pop"); 00320 if(s->nstack == 0){ 00321 werrstr("restore state underflow"); 00322 return -1; 00323 } 00324 e = s->stack[s->nstack-1]; 00325 memmove(s->r, e, s->nr*sizeof(e[0])); 00326 free(e); 00327 s->nstack--; 00328 continue; 00329 00330 case 0x0C: /* def cfa */ 00331 arg1 = dwarfget128(b); 00332 arg2 = dwarfget128(b); 00333 defcfa: 00334 if(trace) werrstr("cfa %ld(r%ld)", arg2, arg1); 00335 if(checkreg(s, arg1) < 0) 00336 return -1; 00337 s->cfa->type = RuleRegOff; 00338 s->cfa->reg = arg1; 00339 s->cfa->offset = arg2; 00340 continue; 00341 00342 case 0x0D: /* def cfa register */ 00343 arg1 = dwarfget128(b); 00344 if(trace) werrstr("cfa reg r%ld", arg1); 00345 if(s->cfa->type != RuleRegOff){ 00346 werrstr("change CFA register but CFA not in register+offset form"); 00347 return -1; 00348 } 00349 if(checkreg(s, arg1) < 0) 00350 return -1; 00351 s->cfa->reg = arg1; 00352 continue; 00353 00354 case 0x0E: /* def cfa offset */ 00355 arg1 = dwarfget128(b); 00356 cfaoffset: 00357 if(trace) werrstr("cfa off %ld", arg1); 00358 if(s->cfa->type != RuleRegOff){ 00359 werrstr("change CFA offset but CFA not in register+offset form"); 00360 return -1; 00361 } 00362 s->cfa->offset = arg1; 00363 continue; 00364 00365 case 0x0F: /* def cfa expression */ 00366 if(trace) werrstr("cfa expr"); 00367 s->cfa->type = RuleLocation; 00368 s->cfa->loc.len = dwarfget128(b); 00369 s->cfa->loc.data = dwarfgetnref(b, s->cfa->loc.len); 00370 continue; 00371 00372 case 0x10: /* def reg expression */ 00373 arg1 = dwarfget128(b); 00374 if(trace) werrstr("reg expr r%ld", arg1); 00375 if(checkreg(s, arg1) < 0) 00376 return -1; 00377 s->r[arg1].type = RuleLocation; 00378 s->r[arg1].loc.len = dwarfget128(b); 00379 s->r[arg1].loc.data = dwarfgetnref(b, s->r[arg1].loc.len); 00380 continue; 00381 00382 case 0x11: /* offset extended */ 00383 arg1 = dwarfget128(b); 00384 arg2 = dwarfget128s(b); 00385 goto offset; 00386 00387 case 0x12: /* cfa sf */ 00388 arg1 = dwarfget128(b); 00389 arg2 = dwarfget128s(b); 00390 goto defcfa; 00391 00392 case 0x13: /* cfa offset sf */ 00393 arg1 = dwarfget128s(b); 00394 goto cfaoffset; 00395 00396 default: /* unknown */ 00397 werrstr("unknown opcode 0x%x in cfa program", c); 00398 return -1; 00399 } 00400 } 00401 /* not reached */ 00402 } 00403 00404 int dwarfcomputecfa(Dwarf *d, DwarfExpr *cfa, PROSSYM_REGISTERS registers, ulong *cfaLocation) 00405 { 00406 switch (cfa->type) { 00407 case RuleRegOff: 00408 *cfaLocation = registers->Registers[cfa->reg] + cfa->offset; 00409 werrstr("cfa reg %d (%x) offset %x = %x", cfa->reg, (ulong)registers->Registers[cfa->reg], cfa->offset, cfaLocation); 00410 break; 00411 default: 00412 werrstr("cfa->type %x", cfa->type); 00413 return -1; 00414 } 00415 00416 return 0; 00417 } 00418 00419 int dwarfregunwind(Dwarf *d, ulong pc, ulong fde, DwarfExpr *cfa, PROSSYM_REGISTERS registers) 00420 { 00421 int i; 00422 State s = { }; 00423 DwarfExpr initr[sizeof(registers->Registers) / sizeof(registers->Registers[0])] = { }; 00424 DwarfExpr r[sizeof(registers->Registers) / sizeof(registers->Registers[0])] = { }; 00425 DwarfExpr ra; 00426 00427 int nr = s.nr = sizeof(registers->Registers) / sizeof(registers->Registers[0]); 00428 s.initr = initr; 00429 s.r = r; 00430 for (i = 0; i < sizeof(r) / sizeof(r[0]); i++) { 00431 r[i].type = RuleRegister; 00432 r[i].offset = registers->Registers[i]; 00433 r[i].reg = i; 00434 } 00435 00436 int res = dwarfunwind(d, pc, cfa, &ra, initr, sizeof(initr) / sizeof(initr[0])); 00437 if (res == -1) return -1; 00438 00439 ulong cfaLocation; 00440 00441 if (dwarfcomputecfa(d, cfa, registers, &cfaLocation) == -1) 00442 return -1; 00443 00444 for (i = 0; i < nr; i++) { 00445 switch (r[i].type) { 00446 case RuleUndef: 00447 werrstr("Undefined register slot %d", i); 00448 assert(FALSE); 00449 break; 00450 case RuleSame: 00451 break; 00452 case RuleRegister: 00453 registers->Registers[i] = registers->Registers[r[i].reg]; 00454 break; 00455 case RuleRegOff: { 00456 BOOLEAN success = 00457 RosSymCallbacks.MemGetProc 00458 (d->pe->fd, 00459 ®isters->Registers[i], 00460 r[i].offset + registers->Registers[r[i].reg], 00461 d->addrsize); 00462 if (!success) return -1; 00463 } break; 00464 case RuleCfaOffset: 00465 { 00466 BOOLEAN success = 00467 RosSymCallbacks.MemGetProc 00468 (d->pe->fd, 00469 ®isters->Registers[i], 00470 r[i].offset + cfaLocation, 00471 d->addrsize); 00472 werrstr("reg[%d] = %x: cfa offset (cfa %x, offset %x) -> @%x", i, (ulong)registers->Registers[i], cfaLocation, initr[i].offset, r[i].offset + cfaLocation); 00473 if (!success) return -1; 00474 } break; 00475 default: 00476 werrstr("We don't yet support cfa rule %d in slot %d", r[i].type, i); 00477 assert(FALSE); 00478 break; 00479 } 00480 } 00481 00482 ulong cfaSpace[4]; 00483 for (i = 0; i < sizeof(cfaSpace) / sizeof(cfaSpace[0]); i++) { 00484 RosSymCallbacks.MemGetProc 00485 (d->pe->fd, &cfaSpace[i], cfaLocation + (i * 4), d->addrsize); 00486 } 00487 werrstr("CFA(%x) [%08x, %08x, %08x, %08x]", 00488 cfaLocation, cfaSpace[0], cfaSpace[1], cfaSpace[2], cfaSpace[3]); 00489 00490 return 0; 00491 } Generated on Fri May 25 2012 04:34:47 for ReactOS by
1.7.6.1
|