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

dwarfcfa.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                  &registers->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                  &registers->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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.