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 #define NTOSAPI 00012 #include <ntddk.h> 00013 #include <reactos/rossym.h> 00014 #include "rossympriv.h" 00015 #include <ntimage.h> 00016 00017 #define NDEBUG 00018 #include <debug.h> 00019 00020 #include "dwarf.h" 00021 00022 #define trace 0 00023 00024 typedef struct State State; 00025 struct State 00026 { 00027 ulong loc; 00028 ulong endloc; 00029 ulong iquantum; 00030 ulong dquantum; 00031 char *augmentation; 00032 int version; 00033 ulong rareg; 00034 DwarfBuf init; 00035 DwarfExpr *cfa; 00036 DwarfExpr *ra; 00037 DwarfExpr *r; 00038 DwarfExpr *initr; 00039 int nr; 00040 DwarfExpr **stack; 00041 int nstack; 00042 }; 00043 00044 static int findfde(Dwarf*, ulong, State*, DwarfBuf*); 00045 static int dexec(DwarfBuf*, State*, int); 00046 00047 int 00048 dwarfunwind(Dwarf *d, ulong pc, DwarfExpr *cfa, DwarfExpr *ra, DwarfExpr *r, int nr) 00049 { 00050 int i, ret; 00051 DwarfBuf fde, b; 00052 DwarfExpr *initr; 00053 State s; 00054 00055 initr = mallocz(nr*sizeof(initr[0]), 1); 00056 if(initr == 0) 00057 return -1; 00058 00059 memset(&s, 0, sizeof s); 00060 s.loc = 0; 00061 s.cfa = cfa; 00062 s.ra = ra; 00063 s.r = r; 00064 s.nr = nr; 00065 00066 if(findfde(d, pc, &s, &fde) < 0){ 00067 free(initr); 00068 return -1; 00069 } 00070 00071 memset(r, 0, nr*sizeof(r[0])); 00072 for(i=0; i<nr; i++) 00073 r[i].type = RuleSame; 00074 if(trace) werrstr("s.init %p-%p, fde %p-%p\n", s.init.p, s.init.ep, fde.p, fde.ep); 00075 b = s.init; 00076 if(dexec(&b, &s, 0) < 0) 00077 goto err; 00078 00079 s.initr = initr; 00080 memmove(initr, r, nr*sizeof(initr[0])); 00081 00082 if(trace) werrstr("s.loc 0x%lux pc 0x%lux\n", s.loc, pc); 00083 while(s.loc < pc){ 00084 if(trace) werrstr("s.loc 0x%lux pc 0x%lux\n", s.loc, pc); 00085 if(dexec(&fde, &s, 1) < 0) 00086 goto err; 00087 } 00088 *ra = s.r[s.rareg]; 00089 00090 ret = 0; 00091 goto out; 00092 00093 err: 00094 ret = -1; 00095 out: 00096 free(initr); 00097 for(i=0; i<s.nstack; i++) 00098 free(s.stack[i]); 00099 free(s.stack); 00100 return ret; 00101 } 00102 00103 /* 00104 * XXX This turns out to be much more expensive than the actual 00105 * running of the machine in dexec. It probably makes sense to 00106 * cache the last 10 or so fde's we've found, since stack traces 00107 * will keep asking for the same info over and over. 00108 */ 00109 static int 00110 findfde(Dwarf *d, ulong pc, State *s, DwarfBuf *fde) 00111 { 00112 static int nbad; 00113 char *aug; 00114 uchar *next; 00115 int i, vers; 00116 ulong len, id, base, size; 00117 DwarfBuf b; 00118 00119 if(d->frame.data == nil){ 00120 werrstr("no frame debugging information"); 00121 return -1; 00122 } 00123 b.d = d; 00124 b.p = d->frame.data; 00125 b.ep = b.p + d->frame.len; 00126 b.addrsize = d->addrsize; 00127 if(b.addrsize == 0) 00128 b.addrsize = 4; /* where should i find this? */ 00129 00130 for(; b.p < b.ep; b.p = next){ 00131 if((i = (b.p - d->frame.data) % b.addrsize)) 00132 b.p += b.addrsize - i; 00133 len = dwarfget4(&b); 00134 if(len > b.ep-b.p){ 00135 werrstr("bad length in cie/fde header"); 00136 return -1; 00137 } 00138 next = b.p+len; 00139 id = dwarfget4(&b); 00140 if(id == 0xFFFFFFFF){ /* CIE */ 00141 vers = dwarfget1(&b); 00142 if(vers != 1 && vers != 2 && vers != 3){ 00143 if(++nbad == 1) 00144 werrstr("unknown cie version %d (wanted 1-3)\n", vers); 00145 continue; 00146 } 00147 aug = dwarfgetstring(&b); 00148 if(aug && *aug){ 00149 if(++nbad == 1) 00150 werrstr("unknown augmentation: %s\n", aug); 00151 continue; 00152 } 00153 s->iquantum = dwarfget128(&b); 00154 s->dquantum = dwarfget128s(&b); 00155 s->rareg = dwarfget128(&b); 00156 if(s->rareg > s->nr){ 00157 werrstr("return address is register %d but only have %d registers", 00158 s->rareg, s->nr); 00159 return -1; 00160 } 00161 s->init.p = b.p; 00162 s->init.ep = next; 00163 }else{ /* FDE */ 00164 base = dwarfgetaddr(&b); 00165 size = dwarfgetaddr(&b); 00166 fde->p = b.p; 00167 fde->ep = next; 00168 s->loc = base; 00169 s->endloc = base+size; 00170 if(base <= pc && pc < base+size) 00171 return 0; 00172 } 00173 } 00174 werrstr("cannot find call frame information for pc 0x%lux", pc); 00175 return -1; 00176 00177 } 00178 00179 static int 00180 checkreg(State *s, long r) 00181 { 00182 if(r < 0 || r >= s->nr){ 00183 werrstr("bad register number 0x%lux", r); 00184 return -1; 00185 } 00186 return 0; 00187 } 00188 00189 static int 00190 dexec(DwarfBuf *b, State *s, int locstop) 00191 { 00192 int c; 00193 long arg1, arg2; 00194 DwarfExpr *e; 00195 00196 for(;;){ 00197 if(b->p == b->ep){ 00198 if(s->initr) 00199 s->loc = s->endloc; 00200 return 0; 00201 } 00202 c = dwarfget1(b); 00203 if(b->p == nil){ 00204 werrstr("ran out of instructions during cfa program"); 00205 if(trace) werrstr("%r\n"); 00206 return -1; 00207 } 00208 if(trace) werrstr("+ loc=0x%lux op 0x%ux ", s->loc, c); 00209 switch(c>>6){ 00210 case 1: /* advance location */ 00211 arg1 = c&0x3F; 00212 advance: 00213 if(trace) werrstr("loc += %ld\n", arg1*s->iquantum); 00214 s->loc += arg1 * s->iquantum; 00215 if(locstop) 00216 return 0; 00217 continue; 00218 00219 case 2: /* offset rule */ 00220 arg1 = c&0x3F; 00221 arg2 = dwarfget128(b); 00222 offset: 00223 if(trace) werrstr("r%ld += %ld\n", arg1, arg2*s->dquantum); 00224 if(checkreg(s, arg1) < 0) 00225 return -1; 00226 s->r[arg1].type = RuleCfaOffset; 00227 s->r[arg1].offset = arg2 * s->dquantum; 00228 continue; 00229 00230 case 3: /* restore initial setting */ 00231 arg1 = c&0x3F; 00232 restore: 00233 if(trace) werrstr("r%ld = init\n", arg1); 00234 if(checkreg(s, arg1) < 0) 00235 return -1; 00236 s->r[arg1] = s->initr[arg1]; 00237 continue; 00238 } 00239 00240 switch(c){ 00241 case 0: /* nop */ 00242 if(trace) werrstr("nop\n"); 00243 continue; 00244 00245 case 0x01: /* set location */ 00246 s->loc = dwarfgetaddr(b); 00247 if(trace) werrstr("loc = 0x%lux\n", s->loc); 00248 if(locstop) 00249 return 0; 00250 continue; 00251 00252 case 0x02: /* advance loc1 */ 00253 arg1 = dwarfget1(b); 00254 goto advance; 00255 00256 case 0x03: /* advance loc2 */ 00257 arg1 = dwarfget2(b); 00258 goto advance; 00259 00260 case 0x04: /* advance loc4 */ 00261 arg1 = dwarfget4(b); 00262 goto advance; 00263 00264 case 0x05: /* offset extended */ 00265 arg1 = dwarfget128(b); 00266 arg2 = dwarfget128(b); 00267 goto offset; 00268 00269 case 0x06: /* restore extended */ 00270 arg1 = dwarfget128(b); 00271 goto restore; 00272 00273 case 0x07: /* undefined */ 00274 arg1 = dwarfget128(b); 00275 if(trace) werrstr("r%ld = undef\n", arg1); 00276 if(checkreg(s, arg1) < 0) 00277 return -1; 00278 s->r[arg1].type = RuleUndef; 00279 continue; 00280 00281 case 0x08: /* same value */ 00282 arg1 = dwarfget128(b); 00283 if(trace) werrstr("r%ld = same\n", arg1); 00284 if(checkreg(s, arg1) < 0) 00285 return -1; 00286 s->r[arg1].type = RuleSame; 00287 continue; 00288 00289 case 0x09: /* register */ 00290 arg1 = dwarfget128(b); 00291 arg2 = dwarfget128(b); 00292 if(trace) werrstr("r%ld = r%ld\n", arg1, arg2); 00293 if(checkreg(s, arg1) < 0 || checkreg(s, arg2) < 0) 00294 return -1; 00295 s->r[arg1].type = RuleRegister; 00296 s->r[arg1].reg = arg2; 00297 continue; 00298 00299 case 0x0A: /* remember state */ 00300 e = malloc(s->nr*sizeof(e[0])); 00301 if(trace) werrstr("push\n"); 00302 if(e == nil) 00303 return -1; 00304 void *newstack = malloc(s->nstack*sizeof(s->stack[0])); 00305 RtlMoveMemory(newstack, s->stack, s->nstack*sizeof(s->stack[0])); 00306 if (newstack) { 00307 free(s->stack); 00308 s->stack = newstack; 00309 } else { 00310 free(e); 00311 return -1; 00312 } 00313 if(b->p == nil){ 00314 free(e); 00315 return -1; 00316 } 00317 s->stack[s->nstack++] = e; 00318 memmove(e, s->r, s->nr*sizeof(e[0])); 00319 continue; 00320 00321 case 0x0B: /* restore state */ 00322 if(trace) werrstr("pop\n"); 00323 if(s->nstack == 0){ 00324 werrstr("restore state underflow"); 00325 return -1; 00326 } 00327 e = s->stack[s->nstack-1]; 00328 memmove(s->r, e, s->nr*sizeof(e[0])); 00329 free(e); 00330 s->nstack--; 00331 continue; 00332 00333 case 0x0C: /* def cfa */ 00334 arg1 = dwarfget128(b); 00335 arg2 = dwarfget128(b); 00336 defcfa: 00337 if(trace) werrstr("cfa %ld(r%ld)\n", arg2, arg1); 00338 if(checkreg(s, arg1) < 0) 00339 return -1; 00340 s->cfa->type = RuleRegOff; 00341 s->cfa->reg = arg1; 00342 s->cfa->offset = arg2; 00343 continue; 00344 00345 case 0x0D: /* def cfa register */ 00346 arg1 = dwarfget128(b); 00347 if(trace) werrstr("cfa reg r%ld\n", arg1); 00348 if(s->cfa->type != RuleRegOff){ 00349 werrstr("change CFA register but CFA not in register+offset form"); 00350 return -1; 00351 } 00352 if(checkreg(s, arg1) < 0) 00353 return -1; 00354 s->cfa->reg = arg1; 00355 continue; 00356 00357 case 0x0E: /* def cfa offset */ 00358 arg1 = dwarfget128(b); 00359 cfaoffset: 00360 if(trace) werrstr("cfa off %ld\n", arg1); 00361 if(s->cfa->type != RuleRegOff){ 00362 werrstr("change CFA offset but CFA not in register+offset form"); 00363 return -1; 00364 } 00365 s->cfa->offset = arg1; 00366 continue; 00367 00368 case 0x0F: /* def cfa expression */ 00369 if(trace) werrstr("cfa expr\n"); 00370 s->cfa->type = RuleLocation; 00371 s->cfa->loc.len = dwarfget128(b); 00372 s->cfa->loc.data = dwarfgetnref(b, s->cfa->loc.len); 00373 continue; 00374 00375 case 0x10: /* def reg expression */ 00376 arg1 = dwarfget128(b); 00377 if(trace) werrstr("reg expr r%ld\n", arg1); 00378 if(checkreg(s, arg1) < 0) 00379 return -1; 00380 s->r[arg1].type = RuleLocation; 00381 s->r[arg1].loc.len = dwarfget128(b); 00382 s->r[arg1].loc.data = dwarfgetnref(b, s->r[arg1].loc.len); 00383 continue; 00384 00385 case 0x11: /* offset extended */ 00386 arg1 = dwarfget128(b); 00387 arg2 = dwarfget128s(b); 00388 goto offset; 00389 00390 case 0x12: /* cfa sf */ 00391 arg1 = dwarfget128(b); 00392 arg2 = dwarfget128s(b); 00393 goto defcfa; 00394 00395 case 0x13: /* cfa offset sf */ 00396 arg1 = dwarfget128s(b); 00397 goto cfaoffset; 00398 00399 default: /* unknown */ 00400 werrstr("unknown opcode 0x%ux in cfa program", c); 00401 return -1; 00402 } 00403 } 00404 /* not reached */ 00405 } 00406 00407 Generated on Sat May 26 2012 04:35:17 for ReactOS by
1.7.6.1
|