Skip to content

Commit 844d828

Browse files
committed
libdrgn: add partial support for .gnu_debugaltlink
Issue osandov#130 reported an "unknown attribute form 0x1f20" from drgn. 0x1f20 is DW_FORM_GNU_ref_alt, which is a reference to a DIE in an alternate file. Similarly, DW_FORM_GNU_strp_alt is a string in an alternate file. The alternate file is specified by the .gnu_debugaltlink section. This is generated by dwz, which is used by at least Fedora and Debian. libdwfl already finds the alternate debug info file, so we can save its .debug_info and .debug_str and use those to support DW_FORM_GNU_ref_alt and DW_FORM_GNU_strp_alt in the DWARF index. Imported units are going to be more work to support in the DWARF index, but this at least lets drgn start up. Signed-off-by: Omar Sandoval <[email protected]>
1 parent aef144c commit 844d828

File tree

3 files changed

+136
-1
lines changed

3 files changed

+136
-1
lines changed

libdrgn/debug_info.c

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -923,6 +923,40 @@ drgn_debug_info_find_sections(struct drgn_debug_info_module *module)
923923
}
924924
}
925925
}
926+
927+
Dwarf *altdwarf = dwarf_getalt(dwarf);
928+
if (altdwarf) {
929+
elf = dwarf_getelf(altdwarf);
930+
if (!elf)
931+
return drgn_error_libdw();
932+
if (elf_getshdrstrndx(elf, &shstrndx))
933+
return drgn_error_libelf();
934+
935+
scn = NULL;
936+
while ((scn = elf_nextscn(elf, scn))) {
937+
GElf_Shdr shdr_mem;
938+
GElf_Shdr *shdr = gelf_getshdr(scn, &shdr_mem);
939+
if (!shdr)
940+
return drgn_error_libelf();
941+
942+
if (shdr->sh_type != SHT_PROGBITS)
943+
continue;
944+
const char *scnname = elf_strptr(elf, shstrndx, shdr->sh_name);
945+
if (!scnname)
946+
return drgn_error_libelf();
947+
948+
/*
949+
* TODO: save more sections and support imported units.
950+
*/
951+
if (strcmp(scnname, ".debug_info") == 0 &&
952+
!module->alt_debug_info)
953+
module->alt_debug_info = scn;
954+
else if (strcmp(scnname, ".debug_str") == 0 &&
955+
!module->alt_debug_str)
956+
module->alt_debug_str = scn;
957+
}
958+
}
959+
926960
return NULL;
927961
}
928962

@@ -951,13 +985,26 @@ drgn_debug_info_precache_sections(struct drgn_debug_info_module *module)
951985
return err;
952986
}
953987
}
988+
if (module->alt_debug_info) {
989+
err = read_elf_section(module->alt_debug_info,
990+
&module->alt_debug_info_data);
991+
if (err)
992+
return err;
993+
}
994+
if (module->alt_debug_str) {
995+
err = read_elf_section(module->alt_debug_str,
996+
&module->alt_debug_str_data);
997+
if (err)
998+
return err;
999+
}
9541000

9551001
/*
9561002
* Truncate any extraneous bytes so that we can assume that a pointer
9571003
* within .debug_{,line_}str is always null-terminated.
9581004
*/
9591005
truncate_null_terminated_section(module->scn_data[DRGN_SCN_DEBUG_STR]);
9601006
truncate_null_terminated_section(module->scn_data[DRGN_SCN_DEBUG_LINE_STR]);
1007+
truncate_null_terminated_section(module->alt_debug_str_data);
9611008
return NULL;
9621009
}
9631010

libdrgn/debug_info.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,11 @@ struct drgn_debug_info_module {
100100
Dwfl_Module *dwfl_module;
101101
struct drgn_platform platform;
102102
Elf_Scn *scns[DRGN_NUM_DEBUG_SCNS];
103+
Elf_Scn *alt_debug_info;
104+
Elf_Scn *alt_debug_str;
103105
Elf_Data *scn_data[DRGN_NUM_DEBUG_SCN_DATA];
106+
Elf_Data *alt_debug_info_data;
107+
Elf_Data *alt_debug_str_data;
104108

105109
/** DWARF debugging information. */
106110
struct drgn_dwarf_module_info dwarf;

libdrgn/dwarf_info.c

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,7 @@ enum drgn_dwarf_index_abbrev_insn {
379379
* Instructions > 0 and <= INSN_MAX_SKIP indicate a number of bytes to
380380
* be skipped over.
381381
*/
382-
INSN_MAX_SKIP = 199,
382+
INSN_MAX_SKIP = 193,
383383

384384
/* These instructions indicate an attribute that can be skipped over. */
385385
INSN_SKIP_BLOCK,
@@ -403,6 +403,8 @@ enum drgn_dwarf_index_abbrev_insn {
403403
INSN_NAME_STRX2,
404404
INSN_NAME_STRX3,
405405
INSN_NAME_STRX4,
406+
INSN_NAME_STRP_ALT4,
407+
INSN_NAME_STRP_ALT8,
406408
INSN_COMP_DIR_STRP4,
407409
INSN_COMP_DIR_STRP8,
408410
INSN_COMP_DIR_LINE_STRP4,
@@ -413,6 +415,8 @@ enum drgn_dwarf_index_abbrev_insn {
413415
INSN_COMP_DIR_STRX2,
414416
INSN_COMP_DIR_STRX3,
415417
INSN_COMP_DIR_STRX4,
418+
INSN_COMP_DIR_STRP_ALT4,
419+
INSN_COMP_DIR_STRP_ALT8,
416420
INSN_STR_OFFSETS_BASE4,
417421
INSN_STR_OFFSETS_BASE8,
418422
INSN_STMT_LIST_LINEPTR4,
@@ -435,6 +439,8 @@ enum drgn_dwarf_index_abbrev_insn {
435439
INSN_SPECIFICATION_REF_UDATA,
436440
INSN_SPECIFICATION_REF_ADDR4,
437441
INSN_SPECIFICATION_REF_ADDR8,
442+
INSN_SPECIFICATION_REF_ALT4,
443+
INSN_SPECIFICATION_REF_ALT8,
438444
INSN_INDIRECT,
439445
INSN_SIBLING_INDIRECT,
440446
INSN_NAME_INDIRECT,
@@ -674,6 +680,8 @@ static struct drgn_error *dw_form_to_insn(struct drgn_dwarf_index_cu *cu,
674680
case DW_FORM_strp:
675681
case DW_FORM_strp_sup:
676682
case DW_FORM_line_strp:
683+
case DW_FORM_GNU_ref_alt:
684+
case DW_FORM_GNU_strp_alt:
677685
*insn_ret = cu->is_64_bit ? 8 : 4;
678686
return NULL;
679687
case DW_FORM_string:
@@ -759,6 +767,16 @@ static struct drgn_error *dw_at_name_to_insn(struct drgn_dwarf_index_cu *cu,
759767
case DW_FORM_strx4:
760768
*insn_ret = INSN_NAME_STRX4;
761769
return NULL;
770+
case DW_FORM_GNU_strp_alt:
771+
if (!cu->module->alt_debug_str_data) {
772+
return binary_buffer_error(bb,
773+
"DW_FORM_GNU_strp_alt without alternate .debug_str section");
774+
}
775+
if (cu->is_64_bit)
776+
*insn_ret = INSN_NAME_STRP_ALT8;
777+
else
778+
*insn_ret = INSN_NAME_STRP_ALT4;
779+
return NULL;
762780
case DW_FORM_indirect:
763781
*insn_ret = INSN_NAME_INDIRECT;
764782
return NULL;
@@ -813,6 +831,16 @@ static struct drgn_error *dw_at_comp_dir_to_insn(struct drgn_dwarf_index_cu *cu,
813831
case DW_FORM_strx4:
814832
*insn_ret = INSN_COMP_DIR_STRX4;
815833
return NULL;
834+
case DW_FORM_GNU_strp_alt:
835+
if (!cu->module->alt_debug_str_data) {
836+
return binary_buffer_error(bb,
837+
"DW_FORM_GNU_strp_alt without alternate .debug_str section");
838+
}
839+
if (cu->is_64_bit)
840+
*insn_ret = INSN_COMP_DIR_STRP_ALT8;
841+
else
842+
*insn_ret = INSN_COMP_DIR_STRP_ALT4;
843+
return NULL;
816844
case DW_FORM_indirect:
817845
*insn_ret = INSN_COMP_DIR_INDIRECT;
818846
return NULL;
@@ -976,6 +1004,16 @@ dw_at_specification_to_insn(struct drgn_dwarf_index_cu *cu,
9761004
cu->address_size);
9771005
}
9781006
return NULL;
1007+
case DW_FORM_GNU_ref_alt:
1008+
if (!cu->module->alt_debug_info_data) {
1009+
return binary_buffer_error(bb,
1010+
"DW_FORM_GNU_ref_alt without alternate .debug_info section");
1011+
}
1012+
if (cu->is_64_bit)
1013+
*insn_ret = INSN_SPECIFICATION_REF_ALT8;
1014+
else
1015+
*insn_ret = INSN_SPECIFICATION_REF_ALT4;
1016+
return NULL;
9791017
case DW_FORM_indirect:
9801018
*insn_ret = INSN_SPECIFICATION_INDIRECT;
9811019
return NULL;
@@ -2092,6 +2130,17 @@ indirect_insn:;
20922130
return err;
20932131
comp_dir = &comp_dir_is_strx;
20942132
break;
2133+
case INSN_COMP_DIR_STRP_ALT4:
2134+
if ((err = binary_buffer_next_u32_into_u64(&buffer->bb,
2135+
&tmp)))
2136+
return err;
2137+
strp_scn = cu->module->alt_debug_str_data;
2138+
goto comp_dir_strp;
2139+
case INSN_COMP_DIR_STRP_ALT8:
2140+
if ((err = binary_buffer_next_u64(&buffer->bb, &tmp)))
2141+
return err;
2142+
strp_scn = cu->module->alt_debug_str_data;
2143+
goto comp_dir_strp;
20952144
case INSN_STR_OFFSETS_BASE4:
20962145
if ((err = binary_buffer_next_u32_into_u64(&buffer->bb,
20972146
&tmp)))
@@ -2135,10 +2184,12 @@ indirect_insn:;
21352184
goto skip;
21362185
case INSN_NAME_STRP4:
21372186
case INSN_NAME_STRX4:
2187+
case INSN_NAME_STRP_ALT4:
21382188
case INSN_DECL_FILE_DATA4:
21392189
skip = 4;
21402190
goto skip;
21412191
case INSN_NAME_STRP8:
2192+
case INSN_NAME_STRP_ALT8:
21422193
case INSN_DECL_FILE_DATA8:
21432194
skip = 8;
21442195
goto skip;
@@ -2194,6 +2245,19 @@ indirect_insn:;
21942245
specification_ref_addr:
21952246
specification = (uintptr_t)debug_info_buffer + tmp;
21962247
break;
2248+
case INSN_SPECIFICATION_REF_ALT4:
2249+
if ((err = binary_buffer_next_u32_into_u64(&buffer->bb,
2250+
&tmp)))
2251+
return err;
2252+
goto specification_ref_alt;
2253+
case INSN_SPECIFICATION_REF_ALT8:
2254+
if ((err = binary_buffer_next_u64(&buffer->bb,
2255+
&tmp)))
2256+
return err;
2257+
specification_ref_alt:
2258+
specification = ((uintptr_t)cu->module->alt_debug_info_data->d_buf
2259+
+ tmp);
2260+
break;
21972261
case INSN_INDIRECT:
21982262
case INSN_SIBLING_INDIRECT:
21992263
case INSN_NAME_INDIRECT:
@@ -2545,14 +2609,32 @@ indirect_insn:;
25452609
return err;
25462610
__builtin_prefetch(name);
25472611
break;
2612+
case INSN_NAME_STRP_ALT4:
2613+
if ((err = binary_buffer_next_u32_into_u64(&buffer->bb,
2614+
&tmp)))
2615+
return err;
2616+
goto name_alt_strp;
2617+
case INSN_NAME_STRP_ALT8:
2618+
if ((err = binary_buffer_next_u64(&buffer->bb, &tmp)))
2619+
return err;
2620+
name_alt_strp:
2621+
if (tmp >= cu->module->alt_debug_str_data->d_size) {
2622+
return binary_buffer_error(&buffer->bb,
2623+
"DW_AT_name is out of bounds");
2624+
}
2625+
name = (const char *)cu->module->alt_debug_str_data->d_buf + tmp;
2626+
__builtin_prefetch(name);
2627+
break;
25482628
case INSN_COMP_DIR_STRP4:
25492629
case INSN_COMP_DIR_LINE_STRP4:
2630+
case INSN_COMP_DIR_STRP_ALT4:
25502631
case INSN_STR_OFFSETS_BASE4:
25512632
case INSN_STMT_LIST_LINEPTR4:
25522633
skip = 4;
25532634
goto skip;
25542635
case INSN_COMP_DIR_STRP8:
25552636
case INSN_COMP_DIR_LINE_STRP8:
2637+
case INSN_COMP_DIR_STRP_ALT8:
25562638
case INSN_STR_OFFSETS_BASE8:
25572639
case INSN_STMT_LIST_LINEPTR8:
25582640
skip = 8;
@@ -2623,13 +2705,15 @@ indirect_insn:;
26232705
goto skip;
26242706
case INSN_SPECIFICATION_REF4:
26252707
case INSN_SPECIFICATION_REF_ADDR4:
2708+
case INSN_SPECIFICATION_REF_ALT4:
26262709
specification = true;
26272710
/* fallthrough */
26282711
case INSN_COMP_DIR_STRX4:
26292712
skip = 4;
26302713
goto skip;
26312714
case INSN_SPECIFICATION_REF8:
26322715
case INSN_SPECIFICATION_REF_ADDR8:
2716+
case INSN_SPECIFICATION_REF_ALT8:
26332717
specification = true;
26342718
skip = 8;
26352719
goto skip;

0 commit comments

Comments
 (0)