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!
23 BasicDwarfBlock
= 1<<1,
29 typedef struct State State
;
41 dwarfpctoline(Dwarf
*d
, DwarfSym
*proc
, ulong pc
, char **file
, char **function
, ulong
*line
)
44 uchar
*prog
, *opcount
, *end
, *dirs
;
45 ulong off
, unit
, len
, vers
, x
, start
, lastline
;
46 int i
, first
, firstline
, op
, a
, l
, quantum
, isstmt
, linebase
, linerange
, opcodebase
, nf
;
50 State emit
, cur
, reset
;
54 memset(proc
, 0, sizeof(*proc
));
56 int runit
= dwarfaddrtounit(d
, pc
, &unit
);
59 int rtag
= dwarflookuptag(d
, unit
, TagCompileUnit
, &sym
);
63 if(!sym
.attrs
.have
.stmtlist
){
64 werrstr("no line mapping information for 0x%x", pc
);
67 off
= sym
.attrs
.stmtlist
;
68 if(off
>= d
->line
.len
){
69 werrstr("bad stmtlist");
73 if(trace
) werrstr("unit 0x%x stmtlist 0x%x", unit
, sym
.attrs
.stmtlist
);
75 memset(&b
, 0, sizeof b
);
77 b
.p
= d
->line
.data
+ off
;
78 b
.ep
= b
.p
+ d
->line
.len
;
79 b
.addrsize
= sym
.b
.addrsize
; /* should i get this from somewhere else? */
82 if(b
.p
==nil
|| b
.p
+len
> b
.ep
|| b
.p
+len
< b
.p
){
90 werrstr("bad dwarf version 0x%x", vers
);
95 if(b
.p
==nil
|| b
.p
+len
> b
.ep
|| b
.p
+len
< b
.p
){
96 werrstr("another bad len");
101 quantum
= dwarfget1(&b
);
102 isstmt
= dwarfget1(&b
);
103 linebase
= (schar
)dwarfget1(&b
);
104 linerange
= (schar
)dwarfget1(&b
);
105 opcodebase
= dwarfget1(&b
);
108 dwarfgetnref(&b
, opcodebase
-1);
110 werrstr("bad opcode chart");
114 /* just skip the files and dirs for now; we'll come back */
121 while(b
.p
!=nil
&& *b
.p
!=0){
129 /* move on to the program */
130 if(b
.p
== nil
|| b
.p
> prog
){
131 werrstr("bad header");
140 reset
.flags
= isstmt
? Isstmt
: 0;
147 if(trace
) werrstr("program @ %lu ... %.*H opbase = %d", b
.p
- d
->line
.data
, b
.ep
-b
.p
, b
.p
, opcodebase
);
152 if(trace
) werrstr("\tline %lu, addr 0x%x, op %d %.10H", cur
.line
, cur
.addr
, op
, b
.p
);
153 if(op
>= opcodebase
){
154 a
= (op
- opcodebase
) / linerange
;
155 l
= (op
- opcodebase
) % linerange
+ linebase
;
157 cur
.addr
+= a
* quantum
;
158 if(trace
) werrstr(" +%d,%d", a
, l
);
162 werrstr("found wrong line mapping 0x%x for pc 0x%x", cur
.addr
, pc
);
163 /* This is an overzealous check. gcc can produce discontiguous ranges
164 and reorder statements, so it's possible for a future line to start
165 ahead of pc and still find a matching one. */
172 if(cur
.addr
> pc
&& !firstline
)
175 werrstr("buffer underflow in line mapping");
179 if(emit
.flags
& EndSequence
){
180 werrstr("found wrong line mapping 0x%x-0x%x for pc 0x%x", start
, cur
.addr
, pc
);
183 cur
.flags
&= ~(BasicDwarfBlock
|PrologueEnd
|EpilogueBegin
);
186 case 0: /* extended op code */
187 if(trace
) werrstr(" ext");
188 len
= dwarfget128(&b
);
190 if(b
.p
== nil
|| end
> b
.ep
|| end
< b
.p
|| len
< 1)
192 switch(dwarfget1(&b
)){
193 case 1: /* end sequence */
194 if(trace
) werrstr(" end");
195 cur
.flags
|= EndSequence
;
197 case 2: /* set address */
198 cur
.addr
= dwarfgetaddr(&b
);
199 if(trace
) werrstr(" set pc 0x%x", cur
.addr
);
201 case 3: /* define file */
202 newf
= malloc(nf
+1*sizeof(f
[0]));
204 RtlMoveMemory(newf
, f
, nf
*sizeof(f
[0]));
209 f
[nf
++] = s
= dwarfgetstring(&b
);
210 DPRINT1("str %s", s
);
214 if(trace
) werrstr(" def file %s", s
);
217 if(b
.p
== nil
|| b
.p
> end
)
222 if(trace
) werrstr(" emit");
224 case 2: /* advance pc */
226 if(trace
) werrstr(" advance pc + %lu", a
*quantum
);
227 cur
.addr
+= a
* quantum
;
229 case 3: /* advance line */
230 l
= dwarfget128s(&b
);
231 if(trace
) werrstr(" advance line + %ld", l
);
234 case 4: /* set file */
235 if(trace
) werrstr(" set file");
236 cur
.file
= dwarfget128s(&b
);
238 case 5: /* set column */
239 if(trace
) werrstr(" set column");
240 cur
.column
= dwarfget128(&b
);
242 case 6: /* negate stmt */
243 if(trace
) werrstr(" negate stmt");
246 case 7: /* set basic block */
247 if(trace
) werrstr(" set basic block");
248 cur
.flags
|= BasicDwarfBlock
;
250 case 8: /* const add pc */
251 a
= (255 - opcodebase
) / linerange
* quantum
;
252 if(trace
) werrstr(" const add pc + %d", a
);
255 case 9: /* fixed advance pc */
257 if(trace
) werrstr(" fixed advance pc + %d", a
);
260 case 10: /* set prologue end */
261 if(trace
) werrstr(" set prologue end");
262 cur
.flags
|= PrologueEnd
;
264 case 11: /* set epilogue begin */
265 if(trace
) werrstr(" set epilogue begin");
266 cur
.flags
|= EpilogueBegin
;
268 case 12: /* set isa */
269 if(trace
) werrstr(" set isa");
270 cur
.isa
= dwarfget128(&b
);
272 default: /* something new - skip it */
273 if(trace
) werrstr(" unknown %d", opcount
[op
]);
274 for(i
=0; i
<opcount
[op
]; i
++)
283 /* finally! the data we seek is in "emit" */
286 werrstr("invalid file index in mapping data");
292 /* skip over first emit.file-2 guys */
294 for(i
=emit
.file
-1; i
> 0 && b
.p
!=nil
&& *b
.p
!=0; i
--){
301 werrstr("problem parsing file data second time (cannot happen)");
306 werrstr("bad file index in mapping data");
311 s
= dwarfgetstring(&b
);
313 i
= dwarfget128(&b
); /* directory */
318 cdir
= sym
.attrs
.have
.compdir
? sym
.attrs
.compdir
: 0;
323 for (x
= 1; b
.p
&& *b
.p
; x
++) {
324 dwarfdir
= dwarfgetstring(&b
);
328 if (!cdir
&& dwarfdir
)
331 char *filefull
= malloc(strlen(cdir
) + strlen(*file
) + 2);
332 strcpy(filefull
, cdir
);
333 strcat(filefull
, "/");
334 strcat(filefull
, *file
);
340 runit
= dwarfaddrtounit(d
, pc
, &unit
);
342 DwarfSym compunit
= { };
343 int renum
= dwarfenumunit(d
, unit
, &compunit
);
346 renum
= dwarfnextsymat(d
, &compunit
, proc
);
348 if (proc
->attrs
.tag
== TagSubprogram
&&
349 proc
->attrs
.have
.name
)
351 if (proc
->attrs
.lowpc
<= pc
&& proc
->attrs
.highpc
> pc
) {
352 *function
= malloc(strlen(proc
->attrs
.name
)+1);
353 strcpy(*function
, proc
->attrs
.name
);
357 renum
= dwarfnextsym(d
, proc
);
361 // Next search by declaration
362 runit
= dwarfaddrtounit(d
, pc
, &unit
);
364 DwarfSym compunit
= { };
365 int renum
= dwarfenumunit(d
, unit
, &compunit
);
368 renum
= dwarfnextsymat(d
, &compunit
, proc
);
370 if (proc
->attrs
.tag
== TagSubprogram
&&
371 proc
->attrs
.have
.name
&&
372 proc
->attrs
.declfile
== emit
.file
)
374 if (proc
->attrs
.declline
<= *line
&&
375 proc
->attrs
.declline
> lastline
) {
377 *function
= malloc(strlen(proc
->attrs
.name
)+1);
378 strcpy(*function
, proc
->attrs
.name
);
381 lastline
= proc
->attrs
.declline
;
383 renum
= dwarfnextsym(d
, proc
);
387 /* free at last, free at last */
392 werrstr("corrupted line mapping for 0x%x", pc
);
398 VOID
RosSymFreeInfo(PROSSYM_LINEINFO LineInfo
)
401 free(LineInfo
->FileName
);
402 LineInfo
->FileName
= NULL
;
403 free(LineInfo
->FunctionName
);
404 LineInfo
->FunctionName
= NULL
;
405 for (i
= 0; i
< sizeof(LineInfo
->Parameters
)/sizeof(LineInfo
->Parameters
[0]); i
++)
406 free(LineInfo
->Parameters
[i
].ValueName
);