Skip to content

Commit 19c0b3c

Browse files
oltolmjrfonseca
authored andcommitted
create aranges if they do not exist
1 parent bdff55a commit 19c0b3c

File tree

3 files changed

+350
-16
lines changed

3 files changed

+350
-16
lines changed

src/mgwhelp/dwarf_find.cpp

Lines changed: 307 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,18 @@
3131

3232
#include "dwarf_find.h"
3333

34+
#include <cassert>
35+
#include <cstdlib>
36+
#include <cstring>
3437
#include <stdlib.h>
38+
#include <vector>
3539

40+
#include "dwarf.h"
41+
#include "libdwarf.h"
3642
#include "outdbg.h"
3743

44+
static int
45+
create_aranges(Dwarf_Debug dbg, std::vector<My_Arange *> &myrec, Dwarf_Error *error);
3846

3947
static char unknown[] = {'?', '?', '\0'};
4048

@@ -167,7 +175,15 @@ dwarf_find_symbol(dwarf_module *dwarf, Dwarf_Addr addr, struct dwarf_symbol_info
167175

168176
Dwarf_Arange arange;
169177
if (dwarf_get_arange(dwarf->aranges, dwarf->arange_count, addr, &arange, &error) != DW_DLV_OK) {
170-
goto no_arange;
178+
if (dwarf->my_aranges.empty()) {
179+
if (create_aranges(dbg, dwarf->my_aranges, &error) == DW_DLV_ERROR) {
180+
goto no_arange;
181+
}
182+
}
183+
if (dwarf_get_arange((Dwarf_Arange *)dwarf->my_aranges.data(), dwarf->my_aranges.size(),
184+
addr, &arange, &error) != DW_DLV_OK) {
185+
goto no_arange;
186+
}
171187
}
172188

173189
Dwarf_Off cu_die_offset;
@@ -204,7 +220,15 @@ dwarf_find_line(dwarf_module *dwarf, Dwarf_Addr addr, struct dwarf_line_info *in
204220

205221
Dwarf_Arange arange;
206222
if (dwarf_get_arange(dwarf->aranges, dwarf->arange_count, addr, &arange, &error) != DW_DLV_OK) {
207-
goto no_arange;
223+
if (dwarf->my_aranges.empty()) {
224+
if (create_aranges(dbg, dwarf->my_aranges, &error) == DW_DLV_ERROR) {
225+
goto no_arange;
226+
}
227+
}
228+
if (dwarf_get_arange((Dwarf_Arange *)dwarf->my_aranges.data(), dwarf->my_aranges.size(),
229+
addr, &arange, &error) != DW_DLV_OK) {
230+
goto no_arange;
231+
}
208232
}
209233

210234
Dwarf_Off cu_die_offset;
@@ -333,3 +357,284 @@ no_die_offset:;
333357
}
334358
return result;
335359
}
360+
361+
static int
362+
getlowhighpc(Dwarf_Die die, Dwarf_Addr *lowpc_out, Dwarf_Addr *highpc_out, Dwarf_Error *error)
363+
{
364+
Dwarf_Addr hipc = 0;
365+
int res = 0;
366+
Dwarf_Half form = 0;
367+
enum Dwarf_Form_Class formclass = DW_FORM_CLASS_UNKNOWN;
368+
369+
res = dwarf_lowpc(die, lowpc_out, error);
370+
if (res == DW_DLV_OK) {
371+
res = dwarf_highpc_b(die, &hipc, &form, &formclass, error);
372+
if (res == DW_DLV_OK) {
373+
if (formclass == DW_FORM_CLASS_CONSTANT) {
374+
hipc += *lowpc_out;
375+
}
376+
*highpc_out = hipc;
377+
return DW_DLV_OK;
378+
}
379+
}
380+
/* Cannot check ranges yet, we don't know the ranges base
381+
offset yet. */
382+
return DW_DLV_NO_ENTRY;
383+
}
384+
385+
/* Based on 'examplev' in 'checkexamples.c'.
386+
There is another example in 'check_comp_dir()' in 'findfuncbypc.c',
387+
but it seems wrong because the base address is not read from 'DW_AT_low_pc' of the CU die.
388+
*/
389+
static int
390+
record_range(Dwarf_Debug dbg,
391+
Dwarf_Die die,
392+
std::vector<My_Arange *> &myrec,
393+
Dwarf_Off info_offset,
394+
Dwarf_Error *error)
395+
{
396+
Dwarf_Signed count = 0;
397+
Dwarf_Off realoffset = 0;
398+
Dwarf_Ranges *rangesbuf = 0;
399+
Dwarf_Unsigned bytecount = 0;
400+
int res = 0;
401+
Dwarf_Unsigned base_address = 0;
402+
Dwarf_Bool have_base_addr = FALSE;
403+
Dwarf_Bool have_rangesoffset = FALSE;
404+
Dwarf_Unsigned rangesoffset = (Dwarf_Unsigned)info_offset;
405+
406+
/* Find the ranges for a specific DIE */
407+
res = dwarf_get_ranges_baseaddress(dbg, die, &have_base_addr, &base_address, &have_rangesoffset,
408+
&rangesoffset, error);
409+
if (res == DW_DLV_ERROR) {
410+
/* Just pretend not an error. */
411+
dwarf_dealloc_error(dbg, *error);
412+
*error = 0;
413+
}
414+
415+
res = dwarf_get_ranges_b(dbg, rangesoffset, die, &realoffset, &rangesbuf, &count, &bytecount,
416+
error);
417+
if (res != DW_DLV_OK) {
418+
return res;
419+
}
420+
Dwarf_Signed i = 0;
421+
for (i = 0; i < count; ++i) {
422+
Dwarf_Ranges *cur = rangesbuf + i;
423+
Dwarf_Addr base = base_address;
424+
Dwarf_Addr lowpc;
425+
Dwarf_Addr highpc;
426+
427+
switch (cur->dwr_type) {
428+
case DW_RANGES_ENTRY:
429+
lowpc = cur->dwr_addr1 + base;
430+
highpc = cur->dwr_addr2 + base;
431+
myrec.push_back(new My_Arange{0, lowpc, highpc - lowpc, info_offset, dbg, 0});
432+
break;
433+
case DW_RANGES_ADDRESS_SELECTION:
434+
base = cur->dwr_addr2;
435+
break;
436+
case DW_RANGES_END:
437+
break;
438+
default:
439+
fprintf(stderr,
440+
"Impossible debug_ranges content!"
441+
" enum val %d \n",
442+
(int)cur->dwr_type);
443+
return DW_DLV_ERROR;
444+
}
445+
}
446+
dwarf_dealloc_ranges(dbg, rangesbuf, count);
447+
448+
return DW_DLV_OK;
449+
}
450+
451+
/* Based on 'example_rnglist_for_attribute()' in 'checkexamples.c'. */
452+
static int
453+
record_rnglist_for_attribute(Dwarf_Debug dbg,
454+
Dwarf_Attribute attr,
455+
Dwarf_Unsigned attrvalue,
456+
Dwarf_Half form,
457+
std::vector<My_Arange *> &myrec,
458+
Dwarf_Off info_offset,
459+
Dwarf_Error *error)
460+
{
461+
/* attrvalue must be the DW_AT_ranges
462+
DW_FORM_rnglistx or DW_FORM_sec_offset value
463+
extracted from attr. */
464+
int res = 0;
465+
Dwarf_Unsigned entries_count;
466+
Dwarf_Unsigned global_offset_of_rle_set;
467+
Dwarf_Rnglists_Head rnglhead = 0;
468+
Dwarf_Unsigned i = 0;
469+
470+
res = dwarf_rnglists_get_rle_head(attr, form, attrvalue, &rnglhead, &entries_count,
471+
&global_offset_of_rle_set, error);
472+
if (res != DW_DLV_OK) {
473+
return res;
474+
}
475+
for (i = 0; i < entries_count; ++i) {
476+
unsigned entrylen = 0;
477+
unsigned code = 0;
478+
Dwarf_Unsigned rawlowpc = 0;
479+
Dwarf_Unsigned rawhighpc = 0;
480+
Dwarf_Bool debug_addr_unavailable = FALSE;
481+
Dwarf_Unsigned lowpc = 0;
482+
Dwarf_Unsigned highpc = 0;
483+
484+
/* Actual addresses are most likely what one
485+
wants to know, not the lengths/offsets
486+
recorded in .debug_rnglists. */
487+
res =
488+
dwarf_get_rnglists_entry_fields_a(rnglhead, i, &entrylen, &code, &rawlowpc, &rawhighpc,
489+
&debug_addr_unavailable, &lowpc, &highpc, error);
490+
if (res != DW_DLV_OK) {
491+
dwarf_dealloc_rnglists_head(rnglhead);
492+
return res;
493+
}
494+
if (code == DW_RLE_end_of_list) {
495+
/* we are done */
496+
break;
497+
}
498+
if (code == DW_RLE_base_addressx || code == DW_RLE_base_address) {
499+
/* We do not need to use these, they
500+
have been accounted for already. */
501+
continue;
502+
}
503+
if (debug_addr_unavailable) {
504+
/* lowpc and highpc are not real addresses */
505+
continue;
506+
}
507+
/* Here do something with lowpc and highpc, these
508+
are real addresses */
509+
myrec.push_back(new My_Arange{0, lowpc, highpc - lowpc, info_offset, dbg, 0});
510+
}
511+
dwarf_dealloc_rnglists_head(rnglhead);
512+
return DW_DLV_OK;
513+
}
514+
515+
/* Based on 'print_die_data_i() in 'simplereader.c'. */
516+
static int
517+
record_rnglist(Dwarf_Debug dbg,
518+
Dwarf_Die cur_die,
519+
std::vector<My_Arange *> &myrec,
520+
Dwarf_Off info_offset,
521+
Dwarf_Error *error)
522+
{
523+
Dwarf_Attribute attr = nullptr;
524+
int res = DW_DLV_OK;
525+
Dwarf_Unsigned attrvalue = 0;
526+
Dwarf_Half form = 0;
527+
528+
res = dwarf_attr(cur_die, DW_AT_ranges, &attr, error);
529+
if (res != DW_DLV_OK)
530+
return res;
531+
532+
res = dwarf_whatform(attr, &form, error);
533+
if (res == DW_DLV_OK) {
534+
if (form == DW_FORM_rnglistx) {
535+
res = dwarf_formudata(attr, &attrvalue, error);
536+
} else {
537+
assert(form == DW_FORM_sec_offset);
538+
res = dwarf_global_formref(attr, &attrvalue, error);
539+
}
540+
if (res == DW_DLV_OK) {
541+
res =
542+
record_rnglist_for_attribute(dbg, attr, attrvalue, form, myrec, info_offset, error);
543+
}
544+
}
545+
dwarf_dealloc(dbg, attr, DW_DLA_ATTR);
546+
547+
return res;
548+
}
549+
550+
static int
551+
record_die(Dwarf_Debug dbg,
552+
Dwarf_Die cur_die,
553+
int is_info,
554+
int in_level,
555+
std::vector<My_Arange *> &myrec,
556+
Dwarf_Error *error)
557+
{
558+
Dwarf_Off info_offset, cu_offset;
559+
Dwarf_Addr lowpc = 0;
560+
Dwarf_Addr highpc = 0;
561+
int res;
562+
563+
res = dwarf_dieoffset(cur_die, &info_offset, error);
564+
if (res != DW_DLV_OK)
565+
return res;
566+
dwarf_die_CU_offset(cur_die, &cu_offset, error);
567+
if (res != DW_DLV_OK)
568+
return res;
569+
info_offset -= cu_offset;
570+
571+
res = getlowhighpc(cur_die, &lowpc, &highpc, error);
572+
if (res == DW_DLV_OK) {
573+
myrec.push_back(new My_Arange{0, lowpc, highpc - lowpc, info_offset, dbg, 0});
574+
} else {
575+
Dwarf_Attribute attr = 0;
576+
Dwarf_Half version = 0;
577+
Dwarf_Half offset_size = 0;
578+
res = dwarf_attr(cur_die, DW_AT_ranges, &attr, error);
579+
if (res != DW_DLV_OK)
580+
return res;
581+
res = dwarf_get_version_of_die(cur_die, &version, &offset_size);
582+
if (res != DW_DLV_OK)
583+
return res;
584+
585+
if (version <= 4) {
586+
res = record_range(dbg, cur_die, myrec, info_offset, error);
587+
} else {
588+
res = record_rnglist(dbg, cur_die, myrec, info_offset, error);
589+
}
590+
if (res != DW_DLV_OK)
591+
return res;
592+
}
593+
return DW_DLV_OK;
594+
}
595+
596+
int
597+
create_aranges(Dwarf_Debug dbg, std::vector<My_Arange *> &myrec, Dwarf_Error *error)
598+
{
599+
Dwarf_Unsigned abbrev_offset = 0;
600+
Dwarf_Half address_size = 0;
601+
Dwarf_Half version_stamp = 0;
602+
Dwarf_Half offset_size = 0;
603+
Dwarf_Half extension_size = 0;
604+
Dwarf_Sig8 signature;
605+
Dwarf_Unsigned typeoffset = 0;
606+
Dwarf_Unsigned next_cu_header = 0;
607+
Dwarf_Half header_cu_type = 0;
608+
Dwarf_Bool is_info = TRUE;
609+
int res = DW_DLV_OK;
610+
611+
while (true) {
612+
Dwarf_Die cu_die = NULL;
613+
Dwarf_Unsigned cu_header_length = 0;
614+
615+
memset(&signature, 0, sizeof(signature));
616+
res = dwarf_next_cu_header_e(dbg, is_info, &cu_die, &cu_header_length, &version_stamp,
617+
&abbrev_offset, &address_size, &offset_size, &extension_size,
618+
&signature, &typeoffset, &next_cu_header, &header_cu_type,
619+
error);
620+
if (res == DW_DLV_ERROR) {
621+
return res;
622+
}
623+
if (res == DW_DLV_NO_ENTRY) {
624+
if (is_info == TRUE) {
625+
/* Done with .debug_info, now check for
626+
.debug_types. */
627+
is_info = FALSE;
628+
continue;
629+
}
630+
/* No more CUs to read! Never found
631+
what we were looking for in either
632+
.debug_info or .debug_types. */
633+
return res;
634+
}
635+
/* We have the cu_die . */
636+
res = record_die(dbg, cu_die, is_info, 0, myrec, error);
637+
dwarf_dealloc_die(cu_die);
638+
}
639+
return res;
640+
}

src/mgwhelp/dwarf_find.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
#include <dwarf.h>
2727
#include <libdwarf.h>
28+
#include <vector>
2829

2930

3031
#ifdef __cplusplus
@@ -43,12 +44,36 @@ struct dwarf_line_info {
4344
unsigned int offset_addr;
4445
};
4546

47+
typedef struct _My_Arange {
48+
/* The segment selector. Only non-zero if Dwarf4, only
49+
meaningful if ar_segment_selector_size non-zero */
50+
Dwarf_Unsigned ar_segment_selector;
51+
52+
/* Starting address of the arange, ie low-pc. */
53+
Dwarf_Addr ar_address;
54+
55+
/* Length of the arange. */
56+
Dwarf_Unsigned ar_length;
57+
58+
/* Offset into .debug_info of the start of the compilation-unit
59+
containing this set of aranges.
60+
Applies only to .debug_info, not .debug_types. */
61+
Dwarf_Off ar_info_offset;
62+
63+
/* Corresponding Dwarf_Debug. */
64+
Dwarf_Debug ar_dbg;
65+
66+
Dwarf_Half ar_segment_selector_size;
67+
} My_Arange;
68+
4669
struct dwarf_module {
4770
Dwarf_Debug dbg;
4871

4972
// cached aranges
5073
Dwarf_Arange *aranges;
5174
Dwarf_Signed arange_count;
75+
76+
std::vector<My_Arange *> my_aranges;
5277
};
5378

5479

0 commit comments

Comments
 (0)