ReactOS 0.4.15-dev-7918-g2a2556c
dwarfcfa.c
Go to the documentation of this file.
1/*
2 * Dwarf call frame unwinding.
3 *
4 * The call frame unwinding values are encoded using a state machine
5 * like the pc<->line mapping, but it's a different machine.
6 * The expressions to generate the old values are similar in function to the
7 * ``dwarf expressions'' used for locations in the code, but of course not
8 * the same encoding.
9 */
10
11#include <ntddk.h>
12#include <reactos/rossym.h>
13#include "rossympriv.h"
14#include <ntimage.h>
15
16#define NDEBUG
17#include <debug.h>
18
19#include "dwarf.h"
20
21#define trace 0
22
23typedef struct State State;
24struct State
25{
38 int nr;
40 int nstack;
41};
42
43static int findfde(Dwarf*, ulong, State*, DwarfBuf*);
44static int dexec(DwarfBuf*, State*, int);
45
46int
48{
49 int i, ret;
50 DwarfBuf fde, b;
51 DwarfExpr *initr;
52 State s;
53
54 initr = mallocz(nr*sizeof(initr[0]), 1);
55 if(initr == 0)
56 return -1;
57
58 memset(&s, 0, sizeof s);
59 s.loc = 0;
60 s.cfa = cfa;
61 s.ra = ra;
62 s.r = r;
63 s.nr = nr;
64
65 if(findfde(d, pc, &s, &fde) < 0){
66 free(initr);
67 return -1;
68 }
69
70 memset(r, 0, nr*sizeof(r[0]));
71 for(i=0; i<nr; i++)
72 r[i].type = RuleSame;
73 if(trace) werrstr("s.init %p-%p, fde %p-%p\n", s.init.p, s.init.ep, fde.p, fde.ep);
74 b = s.init;
75 if(dexec(&b, &s, 0) < 0)
76 goto err;
77
78 s.initr = initr;
79 memmove(initr, r, nr*sizeof(initr[0]));
80
81 if(trace) werrstr("s.loc 0x%lux pc 0x%lux\n", s.loc, pc);
82 while(s.loc < pc){
83 if(trace) werrstr("s.loc 0x%lux pc 0x%lux\n", s.loc, pc);
84 if(dexec(&fde, &s, 1) < 0)
85 goto err;
86 }
87 *ra = s.r[s.rareg];
88
89 ret = 0;
90 goto out;
91
92err:
93 ret = -1;
94out:
95 free(initr);
96 for(i=0; i<s.nstack; i++)
97 free(s.stack[i]);
98 free(s.stack);
99 return ret;
100}
101
102/*
103 * XXX This turns out to be much more expensive than the actual
104 * running of the machine in dexec. It probably makes sense to
105 * cache the last 10 or so fde's we've found, since stack traces
106 * will keep asking for the same info over and over.
107 */
108static int
110{
111 static int nbad;
112 char *aug;
113 uchar *next;
114 int i, vers;
115 ulong len, id, base, size;
116 DwarfBuf b;
117
118 if(d->frame.data == nil){
119 werrstr("no frame debugging information");
120 return -1;
121 }
122 b.d = d;
123 b.p = d->frame.data;
124 b.ep = b.p + d->frame.len;
125 b.addrsize = d->addrsize;
126 if(b.addrsize == 0)
127 b.addrsize = 4; /* where should i find this? */
128
129 for(; b.p < b.ep; b.p = next){
130 if((i = (b.p - d->frame.data) % b.addrsize))
131 b.p += b.addrsize - i;
132 len = dwarfget4(&b);
133 if(len > b.ep-b.p){
134 werrstr("bad length in cie/fde header");
135 return -1;
136 }
137 next = b.p+len;
138 id = dwarfget4(&b);
139 if(id == 0xFFFFFFFF){ /* CIE */
140 vers = dwarfget1(&b);
141 if(vers != 1 && vers != 2 && vers != 3){
142 if(++nbad == 1)
143 werrstr("unknown cie version %d (wanted 1-3)\n", vers);
144 continue;
145 }
146 aug = dwarfgetstring(&b);
147 if(aug && *aug){
148 if(++nbad == 1)
149 werrstr("unknown augmentation: %s\n", aug);
150 continue;
151 }
152 s->iquantum = dwarfget128(&b);
153 s->dquantum = dwarfget128s(&b);
154 s->rareg = dwarfget128(&b);
155 if(s->rareg > s->nr){
156 werrstr("return address is register %d but only have %d registers",
157 s->rareg, s->nr);
158 return -1;
159 }
160 s->init.p = b.p;
161 s->init.ep = next;
162 }else{ /* FDE */
163 base = dwarfgetaddr(&b);
164 size = dwarfgetaddr(&b);
165 fde->p = b.p;
166 fde->ep = next;
167 s->loc = base;
168 s->endloc = base+size;
169 if(base <= pc && pc < base+size)
170 return 0;
171 }
172 }
173 werrstr("cannot find call frame information for pc 0x%lux", pc);
174 return -1;
175
176}
177
178static int
180{
181 if(r < 0 || r >= s->nr){
182 werrstr("bad register number 0x%lux", r);
183 return -1;
184 }
185 return 0;
186}
187
188static int
189dexec(DwarfBuf *b, State *s, int locstop)
190{
191 int c;
192 long arg1, arg2;
193 DwarfExpr *e;
194
195 for(;;){
196 if(b->p == b->ep){
197 if(s->initr)
198 s->loc = s->endloc;
199 return 0;
200 }
201 c = dwarfget1(b);
202 if(b->p == nil){
203 werrstr("ran out of instructions during cfa program");
204 if(trace) werrstr("%r\n");
205 return -1;
206 }
207 if(trace) werrstr("+ loc=0x%lux op 0x%ux ", s->loc, c);
208 switch(c>>6){
209 case 1: /* advance location */
210 arg1 = c&0x3F;
211 advance:
212 if(trace) werrstr("loc += %ld\n", arg1*s->iquantum);
213 s->loc += arg1 * s->iquantum;
214 if(locstop)
215 return 0;
216 continue;
217
218 case 2: /* offset rule */
219 arg1 = c&0x3F;
220 arg2 = dwarfget128(b);
221 offset:
222 if(trace) werrstr("r%ld += %ld\n", arg1, arg2*s->dquantum);
223 if(checkreg(s, arg1) < 0)
224 return -1;
225 s->r[arg1].type = RuleCfaOffset;
226 s->r[arg1].offset = arg2 * s->dquantum;
227 continue;
228
229 case 3: /* restore initial setting */
230 arg1 = c&0x3F;
231 restore:
232 if(trace) werrstr("r%ld = init\n", arg1);
233 if(checkreg(s, arg1) < 0)
234 return -1;
235 s->r[arg1] = s->initr[arg1];
236 continue;
237 }
238
239 switch(c){
240 case 0: /* nop */
241 if(trace) werrstr("nop\n");
242 continue;
243
244 case 0x01: /* set location */
245 s->loc = dwarfgetaddr(b);
246 if(trace) werrstr("loc = 0x%lux\n", s->loc);
247 if(locstop)
248 return 0;
249 continue;
250
251 case 0x02: /* advance loc1 */
252 arg1 = dwarfget1(b);
253 goto advance;
254
255 case 0x03: /* advance loc2 */
256 arg1 = dwarfget2(b);
257 goto advance;
258
259 case 0x04: /* advance loc4 */
260 arg1 = dwarfget4(b);
261 goto advance;
262
263 case 0x05: /* offset extended */
264 arg1 = dwarfget128(b);
265 arg2 = dwarfget128(b);
266 goto offset;
267
268 case 0x06: /* restore extended */
269 arg1 = dwarfget128(b);
270 goto restore;
271
272 case 0x07: /* undefined */
273 arg1 = dwarfget128(b);
274 if(trace) werrstr("r%ld = undef\n", arg1);
275 if(checkreg(s, arg1) < 0)
276 return -1;
277 s->r[arg1].type = RuleUndef;
278 continue;
279
280 case 0x08: /* same value */
281 arg1 = dwarfget128(b);
282 if(trace) werrstr("r%ld = same\n", arg1);
283 if(checkreg(s, arg1) < 0)
284 return -1;
285 s->r[arg1].type = RuleSame;
286 continue;
287
288 case 0x09: /* register */
289 arg1 = dwarfget128(b);
290 arg2 = dwarfget128(b);
291 if(trace) werrstr("r%ld = r%ld\n", arg1, arg2);
292 if(checkreg(s, arg1) < 0 || checkreg(s, arg2) < 0)
293 return -1;
294 s->r[arg1].type = RuleRegister;
295 s->r[arg1].reg = arg2;
296 continue;
297
298 case 0x0A: /* remember state */
299 e = malloc(s->nr*sizeof(e[0]));
300 if(trace) werrstr("push\n");
301 if(e == nil)
302 return -1;
303 void *newstack = malloc(s->nstack*sizeof(s->stack[0]));
304 RtlMoveMemory(newstack, s->stack, s->nstack*sizeof(s->stack[0]));
305 if (newstack) {
306 free(s->stack);
307 s->stack = newstack;
308 } else {
309 free(e);
310 return -1;
311 }
312 if(b->p == nil){
313 free(e);
314 return -1;
315 }
316 s->stack[s->nstack++] = e;
317 memmove(e, s->r, s->nr*sizeof(e[0]));
318 continue;
319
320 case 0x0B: /* restore state */
321 if(trace) werrstr("pop\n");
322 if(s->nstack == 0){
323 werrstr("restore state underflow");
324 return -1;
325 }
326 e = s->stack[s->nstack-1];
327 memmove(s->r, e, s->nr*sizeof(e[0]));
328 free(e);
329 s->nstack--;
330 continue;
331
332 case 0x0C: /* def cfa */
333 arg1 = dwarfget128(b);
334 arg2 = dwarfget128(b);
335 defcfa:
336 if(trace) werrstr("cfa %ld(r%ld)\n", arg2, arg1);
337 if(checkreg(s, arg1) < 0)
338 return -1;
339 s->cfa->type = RuleRegOff;
340 s->cfa->reg = arg1;
341 s->cfa->offset = arg2;
342 continue;
343
344 case 0x0D: /* def cfa register */
345 arg1 = dwarfget128(b);
346 if(trace) werrstr("cfa reg r%ld\n", arg1);
347 if(s->cfa->type != RuleRegOff){
348 werrstr("change CFA register but CFA not in register+offset form");
349 return -1;
350 }
351 if(checkreg(s, arg1) < 0)
352 return -1;
353 s->cfa->reg = arg1;
354 continue;
355
356 case 0x0E: /* def cfa offset */
357 arg1 = dwarfget128(b);
358 cfaoffset:
359 if(trace) werrstr("cfa off %ld\n", arg1);
360 if(s->cfa->type != RuleRegOff){
361 werrstr("change CFA offset but CFA not in register+offset form");
362 return -1;
363 }
364 s->cfa->offset = arg1;
365 continue;
366
367 case 0x0F: /* def cfa expression */
368 if(trace) werrstr("cfa expr\n");
369 s->cfa->type = RuleLocation;
370 s->cfa->loc.len = dwarfget128(b);
371 s->cfa->loc.data = dwarfgetnref(b, s->cfa->loc.len);
372 continue;
373
374 case 0x10: /* def reg expression */
375 arg1 = dwarfget128(b);
376 if(trace) werrstr("reg expr r%ld\n", arg1);
377 if(checkreg(s, arg1) < 0)
378 return -1;
379 s->r[arg1].type = RuleLocation;
380 s->r[arg1].loc.len = dwarfget128(b);
381 s->r[arg1].loc.data = dwarfgetnref(b, s->r[arg1].loc.len);
382 continue;
383
384 case 0x11: /* offset extended */
385 arg1 = dwarfget128(b);
387 goto offset;
388
389 case 0x12: /* cfa sf */
390 arg1 = dwarfget128(b);
392 goto defcfa;
393
394 case 0x13: /* cfa offset sf */
396 goto cfaoffset;
397
398 default: /* unknown */
399 werrstr("unknown opcode 0x%ux in cfa program", c);
400 return -1;
401 }
402 }
403 /* not reached */
404}
405
406
unsigned char uchar
Definition: Unfrag.h:59
_STLP_MOVE_TO_STD_NAMESPACE void _STLP_CALL advance(_InputIterator &__i, _Distance __n)
#define free
Definition: debug_ros.c:5
#define malloc
Definition: debug_ros.c:4
unsigned long ulong
Definition: linux.h:275
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
GLdouble s
Definition: gl.h:2039
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
GLsizeiptr size
Definition: glext.h:5919
GLuint GLuint GLuint GLuint arg1
Definition: glext.h:9513
const GLubyte * c
Definition: glext.h:8905
GLuint GLuint GLuint GLuint GLuint GLuint GLuint arg2
Definition: glext.h:9514
GLboolean GLboolean GLboolean b
Definition: glext.h:6204
GLenum GLsizei len
Definition: glext.h:6722
GLuint id
Definition: glext.h:5910
GLintptr offset
Definition: glext.h:5920
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define d
Definition: ke_i.h:81
#define e
Definition: ke_i.h:82
#define c
Definition: ke_i.h:80
#define b
Definition: ke_i.h:79
#define memmove(s1, s2, n)
Definition: mkisofs.h:881
ULONG nr
Definition: thread.c:7
static unsigned __int64 next
Definition: rand_nt.c:6
#define err(...)
static FILE * out
Definition: regtests2xml.c:44
static int findfde(Dwarf *, ulong, State *, DwarfBuf *)
Definition: dwarfcfa.c:109
#define trace
Definition: dwarfcfa.c:21
static int checkreg(State *s, long r)
Definition: dwarfcfa.c:179
int dwarfunwind(Dwarf *d, ulong pc, DwarfExpr *cfa, DwarfExpr *ra, DwarfExpr *r, int nr)
Definition: dwarfcfa.c:47
static int dexec(DwarfBuf *, State *, int)
Definition: dwarfcfa.c:189
#define werrstr(str,...)
Definition: compat.h:34
#define nil
Definition: compat.h:23
#define mallocz(x, y)
Definition: compat.h:36
#define memset(x, y, z)
Definition: compat.h:39
ulong dwarfget128(DwarfBuf *)
Definition: dwarfget.c:152
ulong dwarfget2(DwarfBuf *)
Definition: dwarfget.c:81
char * dwarfgetstring(DwarfBuf *)
Definition: dwarfget.c:54
ulong dwarfget1(DwarfBuf *)
Definition: dwarfget.c:17
long dwarfget128s(DwarfBuf *)
Definition: dwarfget.c:197
ulong dwarfgetaddr(DwarfBuf *)
Definition: dwarfget.c:123
uchar * dwarfgetnref(DwarfBuf *, ulong)
Definition: dwarfget.c:40
@ RuleLocation
Definition: dwarf.h:363
@ RuleRegOff
Definition: dwarf.h:362
@ RuleRegister
Definition: dwarf.h:361
@ RuleSame
Definition: dwarf.h:359
@ RuleCfaOffset
Definition: dwarf.h:360
@ RuleUndef
Definition: dwarf.h:358
ulong dwarfget4(DwarfBuf *)
Definition: dwarfget.c:95
uchar * p
Definition: dwarf.h:210
uchar * ep
Definition: dwarf.h:211
Definition: dwarf.h:437
char * augmentation
Definition: dwarfcfa.c:30
int nstack
Definition: dwarfcfa.c:40
DwarfExpr * r
Definition: dwarfcfa.c:36
int nr
Definition: dwarfcfa.c:38
ulong loc
Definition: dwarfcfa.c:26
ulong dquantum
Definition: dwarfcfa.c:29
DwarfBuf init
Definition: dwarfcfa.c:33
DwarfExpr * ra
Definition: dwarfcfa.c:35
ulong endloc
Definition: dwarfcfa.c:27
ulong iquantum
Definition: dwarfcfa.c:28
ulong rareg
Definition: dwarfcfa.c:32
DwarfExpr ** stack
Definition: dwarfcfa.c:39
DwarfExpr * initr
Definition: dwarfcfa.c:37
int version
Definition: dwarfcfa.c:31
DwarfExpr * cfa
Definition: dwarfcfa.c:34
#define RtlMoveMemory(Destination, Source, Length)
Definition: typedefs.h:264
int ret