2 * Dwarf pc to source line conversion.
4 * Maybe should do the reverse here, but what should the interface look like?
5 * One possibility is to use the Plan 9 line2addr interface:
7 * long line2addr(ulong line, ulong basepc)
9 * which returns the smallest pc > basepc with line number line (ignoring file name).
11 * The encoding may be small, but it sure isn't simple!
16 #include <reactos/rossym.h>
17 #include "rossympriv.h"
31 BasicDwarfBlock
= 1<<1,
37 typedef struct State State
;
49 dwarfpctoline(Dwarf
*d
, DwarfSym
*proc
, ulong pc
, char **file
, char **function
, ulong
*line
)
52 uchar
*prog
, *opcount
, *end
, *dirs
;
53 ulong off
, unit
, len
, vers
, x
, start
, lastline
;
54 int i
, first
, firstline
, op
, a
, l
, quantum
, isstmt
, linebase
, linerange
, opcodebase
, nf
;
58 State emit
, cur
, reset
;
62 memset(proc
, 0, sizeof(*proc
));
64 int runit
= dwarfaddrtounit(d
, pc
, &unit
);
67 int rtag
= dwarflookuptag(d
, unit
, TagCompileUnit
, &sym
);
71 if(!sym
.attrs
.have
.stmtlist
){
72 werrstr("no line mapping information for 0x%x", pc
);
75 off
= sym
.attrs
.stmtlist
;
76 if(off
>= d
->line
.len
){
77 werrstr("bad stmtlist");
81 if(trace
) werrstr("unit 0x%x stmtlist 0x%x", unit
, sym
.attrs
.stmtlist
);
83 memset(&b
, 0, sizeof b
);
85 b
.p
= d
->line
.data
+ off
;
86 b
.ep
= b
.p
+ d
->line
.len
;
87 b
.addrsize
= sym
.b
.addrsize
; /* should i get this from somewhere else? */
90 if(b
.p
==nil
|| b
.p
+len
> b
.ep
|| b
.p
+len
< b
.p
){
98 werrstr("bad dwarf version 0x%x", vers
);
103 if(b
.p
==nil
|| b
.p
+len
> b
.ep
|| b
.p
+len
< b
.p
){
104 werrstr("another bad len");
109 quantum
= dwarfget1(&b
);
110 isstmt
= dwarfget1(&b
);
111 linebase
= (schar
)dwarfget1(&b
);
112 linerange
= (schar
)dwarfget1(&b
);
113 opcodebase
= dwarfget1(&b
);
116 dwarfgetnref(&b
, opcodebase
-1);
118 werrstr("bad opcode chart");
122 /* just skip the files and dirs for now; we'll come back */
129 while(b
.p
!=nil
&& *b
.p
!=0){
137 /* move on to the program */
138 if(b
.p
== nil
|| b
.p
> prog
){
139 werrstr("bad header");
148 reset
.flags
= isstmt
? Isstmt
: 0;
155 if(trace
) werrstr("program @ %lu ... %.*H opbase = %d", b
.p
- d
->line
.data
, b
.ep
-b
.p
, b
.p
, opcodebase
);
160 if(trace
) werrstr("\tline %lu, addr 0x%x, op %d %.10H", cur
.line
, cur
.addr
, op
, b
.p
);
161 if(op
>= opcodebase
){
162 a
= (op
- opcodebase
) / linerange
;
163 l
= (op
- opcodebase
) % linerange
+ linebase
;
165 cur
.addr
+= a
* quantum
;
166 if(trace
) werrstr(" +%d,%d", a
, l
);
170 werrstr("found wrong line mapping 0x%x for pc 0x%x", cur
.addr
, pc
);
171 /* This is an overzealous check. gcc can produce discontiguous ranges
172 and reorder statements, so it's possible for a future line to start
173 ahead of pc and still find a matching one. */
180 if(cur
.addr
> pc
&& !firstline
)
183 werrstr("buffer underflow in line mapping");
187 if(emit
.flags
& EndSequence
){
188 werrstr("found wrong line mapping 0x%x-0x%x for pc 0x%x", start
, cur
.addr
, pc
);
191 cur
.flags
&= ~(BasicDwarfBlock
|PrologueEnd
|EpilogueBegin
);
194 case 0: /* extended op code */
195 if(trace
) werrstr(" ext");
196 len
= dwarfget128(&b
);
198 if(b
.p
== nil
|| end
> b
.ep
|| end
< b
.p
|| len
< 1)
200 switch(dwarfget1(&b
)){
201 case 1: /* end sequence */
202 if(trace
) werrstr(" end");
203 cur
.flags
|= EndSequence
;
205 case 2: /* set address */
206 cur
.addr
= dwarfgetaddr(&b
);
207 if(trace
) werrstr(" set pc 0x%x", cur
.addr
);
209 case 3: /* define file */
210 newf
= malloc(nf
+1*sizeof(f
[0]));
212 RtlMoveMemory(newf
, f
, nf
*sizeof(f
[0]));
217 f
[nf
++] = s
= dwarfgetstring(&b
);
218 DPRINT1("str %s", s
);
222 if(trace
) werrstr(" def file %s", s
);
225 if(b
.p
== nil
|| b
.p
> end
)
230 if(trace
) werrstr(" emit");
232 case 2: /* advance pc */
234 if(trace
) werrstr(" advance pc + %lu", a
*quantum
);
235 cur
.addr
+= a
* quantum
;
237 case 3: /* advance line */
238 l
= dwarfget128s(&b
);
239 if(trace
) werrstr(" advance line + %ld", l
);
242 case 4: /* set file */
243 if(trace
) werrstr(" set file");
244 cur
.file
= dwarfget128s(&b
);
246 case 5: /* set column */
247 if(trace
) werrstr(" set column");
248 cur
.column
= dwarfget128(&b
);
250 case 6: /* negate stmt */
251 if(trace
) werrstr(" negate stmt");
254 case 7: /* set basic block */
255 if(trace
) werrstr(" set basic block");
256 cur
.flags
|= BasicDwarfBlock
;
258 case 8: /* const add pc */
259 a
= (255 - opcodebase
) / linerange
* quantum
;
260 if(trace
) werrstr(" const add pc + %d", a
);
263 case 9: /* fixed advance pc */
265 if(trace
) werrstr(" fixed advance pc + %d", a
);
268 case 10: /* set prologue end */
269 if(trace
) werrstr(" set prologue end");
270 cur
.flags
|= PrologueEnd
;
272 case 11: /* set epilogue begin */
273 if(trace
) werrstr(" set epilogue begin");
274 cur
.flags
|= EpilogueBegin
;
276 case 12: /* set isa */
277 if(trace
) werrstr(" set isa");
278 cur
.isa
= dwarfget128(&b
);
280 default: /* something new - skip it */
281 if(trace
) werrstr(" unknown %d", opcount
[op
]);
282 for(i
=0; i
<opcount
[op
]; i
++)
291 /* finally! the data we seek is in "emit" */
294 werrstr("invalid file index in mapping data");
300 /* skip over first emit.file-2 guys */
302 for(i
=emit
.file
-1; i
> 0 && b
.p
!=nil
&& *b
.p
!=0; i
--){
309 werrstr("problem parsing file data second time (cannot happen)");
314 werrstr("bad file index in mapping data");
319 s
= dwarfgetstring(&b
);
321 i
= dwarfget128(&b
); /* directory */
326 cdir
= sym
.attrs
.have
.compdir
? sym
.attrs
.compdir
: 0;
331 for (x
= 1; b
.p
&& *b
.p
; x
++) {
332 dwarfdir
= dwarfgetstring(&b
);
336 if (!cdir
&& dwarfdir
)
339 char *filefull
= malloc(strlen(cdir
) + strlen(*file
) + 2);
340 strcpy(filefull
, cdir
);
341 strcat(filefull
, "/");
342 strcat(filefull
, *file
);
348 runit
= dwarfaddrtounit(d
, pc
, &unit
);
350 DwarfSym compunit
= { };
351 int renum
= dwarfenumunit(d
, unit
, &compunit
);
354 renum
= dwarfnextsymat(d
, &compunit
, proc
);
356 if (proc
->attrs
.tag
== TagSubprogram
&&
357 proc
->attrs
.have
.name
)
359 if (proc
->attrs
.lowpc
<= pc
&& proc
->attrs
.highpc
> pc
) {
360 *function
= malloc(strlen(proc
->attrs
.name
)+1);
361 strcpy(*function
, proc
->attrs
.name
);
365 renum
= dwarfnextsym(d
, proc
);
369 // Next search by declaration
370 runit
= dwarfaddrtounit(d
, pc
, &unit
);
372 DwarfSym compunit
= { };
373 int renum
= dwarfenumunit(d
, unit
, &compunit
);
376 renum
= dwarfnextsymat(d
, &compunit
, proc
);
378 if (proc
->attrs
.tag
== TagSubprogram
&&
379 proc
->attrs
.have
.name
&&
380 proc
->attrs
.declfile
== emit
.file
)
382 if (proc
->attrs
.declline
<= *line
&&
383 proc
->attrs
.declline
> lastline
) {
385 *function
= malloc(strlen(proc
->attrs
.name
)+1);
386 strcpy(*function
, proc
->attrs
.name
);
389 lastline
= proc
->attrs
.declline
;
391 renum
= dwarfnextsym(d
, proc
);
395 /* free at last, free at last */
400 werrstr("corrupted line mapping for 0x%x", pc
);
406 VOID
RosSymFreeInfo(PROSSYM_LINEINFO LineInfo
)
409 free(LineInfo
->FileName
);
410 LineInfo
->FileName
= NULL
;
411 free(LineInfo
->FunctionName
);
412 LineInfo
->FunctionName
= NULL
;
413 for (i
= 0; i
< sizeof(LineInfo
->Parameters
)/sizeof(LineInfo
->Parameters
[0]); i
++)
414 free(LineInfo
->Parameters
[i
].ValueName
);