[PATCH v3] binutils/dwarf: Print embedded source, when available
Will Hawkins
hawkinsw@obs.cr
Tue Apr 21 02:02:02 GMT 2026
v3 should contain a test that passes on aarch64 as well as x86_64. Sorry
for the hassle!
Hope everyone had a great Monday!
Will
Signed-off-by: Will Hawkins <hawkinsw@obs.cr>
---
v3: Fixed failing test on aarch64.
v2: Fix variable scoping, name of line number header entry; add test.
binutils/dwarf.c | 34 ++-
.../binutils-all/dwarf-embedded-source.S | 240 ++++++++++++++++++
.../dwarf-embedded-source.rawline | 13 +
binutils/testsuite/binutils-all/objdump.exp | 24 ++
include/dwarf2.h | 2 +
5 files changed, 308 insertions(+), 5 deletions(-)
create mode 100644 binutils/testsuite/binutils-all/dwarf-embedded-source.S
create mode 100644 binutils/testsuite/binutils-all/dwarf-embedded-source.rawline
diff --git a/binutils/dwarf.c b/binutils/dwarf.c
index fa8dce25..6e6a82e4 100644
--- a/binutils/dwarf.c
+++ b/binutils/dwarf.c
@@ -5847,6 +5847,10 @@ display_formatted_table (unsigned char *data,
case DW_LNCT_MD5:
printf (_("\tMD5\t\t\t"));
break;
+ case DW_LNCT_LLVM_source:
+ case DW_LNCT_source:
+ /* Skip source ... display on next line. */
+ break;
default:
printf (_("\t(Unknown format content type %" PRIu64 ")"),
content_type);
@@ -5861,8 +5865,10 @@ display_formatted_table (unsigned char *data,
unsigned char *datapass = data;
printf (" %d", last_entry++);
- /* Delay displaying name as the last entry for better screen layout. */
- for (namepass = 0; namepass < 2; namepass++)
+ /* Delay displaying name/source as the last entry for better screen
+ layout. */
+ int namesourcepass;
+ for (namesourcepass = 0; namesourcepass < 3; namesourcepass++)
{
format = format_start;
data = datapass;
@@ -5872,13 +5878,31 @@ display_formatted_table (unsigned char *data,
READ_ULEB (content_type, format, end);
READ_ULEB (form, format, end);
- bool do_loc = (content_type == DW_LNCT_path) != (namepass == 1);
+
+ bool do_loc = (content_type == DW_LNCT_path)
+ != (namesourcepass == 1);
+ do_loc |= (content_type == DW_LNCT_LLVM_source
+ || content_type == DW_LNCT_source)
+ != (namesourcepass == 2);
+
+ char delimiter = '\t';
+
+ /* Print Source last (if available) and print it
+ starting on the next line. */
+ if (namesourcepass == 2 && (content_type == DW_LNCT_LLVM_source
+ || content_type == DW_LNCT_source))
+ {
+ delimiter = ' ';
+ putchar ('\n');
+ printf (" Source:");
+ }
data = read_and_display_attr_value (0, form, 0, start, data, end,
0, linfo->li_address_size,
linfo->li_offset_size,
linfo->li_version, NULL,
- do_loc, section, NULL, '\t',
- -1, false, 0, 0, false);
+ do_loc, section, NULL,
+ delimiter, -1, false, 0, 0,
+ false);
}
}
diff --git a/binutils/testsuite/binutils-all/dwarf-embedded-source.S b/binutils/testsuite/binutils-all/dwarf-embedded-source.S
new file mode 100644
index 00000000..71273636
--- /dev/null
+++ b/binutils/testsuite/binutils-all/dwarf-embedded-source.S
@@ -0,0 +1,240 @@
+ .text
+ .file "small.c"
+ .globl main
+ .p2align 4, 0x90
+ .type main,@function
+main:
+.Lbegin_func_main:
+.Lend_func_main:
+ .size main, .Lend_func_main-main
+ .section .debug_abbrev,"",@progbits
+ .byte 1 /* Abbreviation Code */
+ .byte 17 /* DW_TAG_compile_unit */
+ .byte 1 /* DW_CHILDREN_yes */
+ .byte 37 /* DW_AT_producer */
+ .byte 37 /* DW_FORM_strx1 */
+ .byte 19 /* DW_AT_language */
+ .byte 5 /* DW_FORM_data2 */
+ .byte 3 /* DW_AT_name */
+ .byte 37 /* DW_FORM_strx1 */
+ .byte 114 /* DW_AT_str_offsets_base */
+ .byte 23 /* DW_FORM_sec_offset */
+ .byte 16 /* DW_AT_stmt_list */
+ .byte 23 /* DW_FORM_sec_offset */
+ .byte 27 /* DW_AT_comp_dir */
+ .byte 37 /* DW_FORM_strx1 */
+ .byte 17 /* DW_AT_low_pc */
+ .byte 27 /* DW_FORM_addrx */
+ .byte 18 /* DW_AT_high_pc */
+ .byte 6 /* DW_FORM_data4 */
+ .byte 115 /* DW_AT_addr_base */
+ .byte 23 /* DW_FORM_sec_offset */
+ .byte 0 /* EOM(1) */
+ .byte 0 /* EOM(2) */
+ .byte 2 /* Abbreviation Code */
+ .byte 46 /* DW_TAG_subprogram */
+ .byte 0 /* DW_CHILDREN_no */
+ .byte 17 /* DW_AT_low_pc */
+ .byte 27 /* DW_FORM_addrx */
+ .byte 18 /* DW_AT_high_pc */
+ .byte 6 /* DW_FORM_data4 */
+ .byte 64 /* DW_AT_frame_base */
+ .byte 24 /* DW_FORM_exprloc */
+ .byte 3 /* DW_AT_name */
+ .byte 37 /* DW_FORM_strx1 */
+ .byte 58 /* DW_AT_decl_file */
+ .byte 11 /* DW_FORM_data1 */
+ .byte 59 /* DW_AT_decl_line */
+ .byte 11 /* DW_FORM_data1 */
+ .byte 73 /* DW_AT_type */
+ .byte 19 /* DW_FORM_ref4 */
+ .byte 63 /* DW_AT_external */
+ .byte 25 /* DW_FORM_flag_present */
+ .byte 0 /* EOM(1) */
+ .byte 0 /* EOM(2) */
+ .byte 3 /* Abbreviation Code */
+ .byte 36 /* DW_TAG_base_type */
+ .byte 0 /* DW_CHILDREN_no */
+ .byte 3 /* DW_AT_name */
+ .byte 37 /* DW_FORM_strx1 */
+ .byte 62 /* DW_AT_encoding */
+ .byte 11 /* DW_FORM_data1 */
+ .byte 11 /* DW_AT_byte_size */
+ .byte 11 /* DW_FORM_data1 */
+ .byte 0 /* EOM(1) */
+ .byte 0 /* EOM(2) */
+ .byte 0 /* EOM(3) */
+ .section .debug_info,"",@progbits
+.Lcu_begin0:
+ .long .Ldebug_info_end0-.Ldebug_info_start0 /* Length of Unit */
+.Ldebug_info_start0:
+ .short 5 /* DWARF version number */
+ .byte 1 /* DWARF Unit Type */
+ .byte 8 /* Address Size (in bytes) */
+ .long .debug_abbrev /* Offset Into Abbrev. Section */
+ .byte 1 /* Abbrev [1] 0xc:0x2b DW_TAG_compile_unit */
+ .byte 0 /* DW_AT_producer */
+ .short 29 /* DW_AT_language */
+ .byte 1 /* DW_AT_name */
+ .long .Lstr_offsets_base0 /* DW_AT_str_offsets_base */
+ .long .Lline_table_start0 /* DW_AT_stmt_list */
+ .byte 2 /* DW_AT_comp_dir */
+ .byte 0 /* DW_AT_low_pc */
+ .long .Lend_func_main-.Lbegin_func_main /* DW_AT_high_pc */
+ .long .Laddr_table_base0 /* DW_AT_addr_base */
+ .byte 2 /* Abbrev [2] 0x23:0xf DW_TAG_subprogram */
+ .byte 0 /* DW_AT_low_pc */
+ .long .Lend_func_main-.Lbegin_func_main /* DW_AT_high_pc */
+ .byte 1 /* DW_AT_frame_base */
+ .byte 86
+ .byte 3 /* DW_AT_name */
+ .byte 0 /* DW_AT_decl_file */
+ .byte 1 /* DW_AT_decl_line */
+ .long 50 /* DW_AT_type */
+ /* DW_AT_external */
+ .byte 3 /* Abbrev [3] 0x32:0x4 DW_TAG_base_type */
+ .byte 4 /* DW_AT_name */
+ .byte 5 /* DW_AT_encoding */
+ .byte 4 /* DW_AT_byte_size */
+ .byte 0 /* End Of Children Mark */
+.Ldebug_info_end0:
+ .section .debug_str_offsets,"",@progbits
+ .long 24 /* Length of String Offsets Set */
+ .short 5
+ .short 0
+.Lstr_offsets_base0:
+ .section .debug_str,"MS",@progbits,1
+.Linfo_string0:
+ .asciz "clang (with hand edits)" /* string offset=0 */
+.Linfo_string1:
+ .asciz "small.c" /* string offset=44 */
+.Linfo_string2:
+ .asciz "/path/to/code/"
+.Linfo_string3:
+ .asciz "main" /* string offset=77 */
+.Linfo_string4:
+ .asciz "int" /* string offset=82 */
+ .section .debug_str_offsets,"",@progbits
+ .long .Linfo_string0
+ .long .Linfo_string1
+ .long .Linfo_string2
+ .long .Linfo_string3
+ .long .Linfo_string4
+ .section .debug_line_str,"MS",@progbits,1
+.Lline_string1:
+ .asciz "/path/to/code/" /* string offset=0 */
+.Lline_string2:
+ .asciz "small.c" /* string offset=15 */
+.Lline_string3:
+ .asciz "int main() {\n return 0;\n}\n"/* string offset=23 */
+ .section .debug_addr,"",@progbits
+ .long .Ldebug_addr_end0-.Ldebug_addr_start0 /* Length of contribution */
+.Ldebug_addr_start0:
+ .short 5 /* DWARF version number */
+ .byte 8 /* Address size */
+ .byte 0 /* Segment selector size */
+.Laddr_table_base0:
+ .quad .Lbegin_func_main
+.Ldebug_addr_end0:
+ .section .debug_line,"",@progbits
+.Lline_table_start0:
+ .byte 0x60
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x05
+ .byte 0x00
+ .byte 0x08
+ .byte 0x00
+ .byte 0x3E
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x01
+ .byte 0x01
+ .byte 0x01
+ .byte 0xfb
+ .byte 0x0e
+ .byte 0x0d
+ .byte 0x00
+ .byte 0x01
+ .byte 0x01
+ .byte 0x01
+ .byte 0x01
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x01
+ .byte 0x00
+ .byte 0x00
+ .byte 0x01
+ .byte 0x01
+ .byte 0x01
+ .byte 0x1f
+ .byte 0x01
+ .byte 0x00 /* Offset to directory. */
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x04
+ .byte 0x01
+ .byte 0x1f
+ .byte 0x02
+ .byte 0x0f /* Offset to filename. */
+ .byte 0x05
+ .byte 0x1e
+ .byte 0x81
+ .byte 0x40
+ .byte 0x1f
+ .byte 0x01
+ .byte 0x0f
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x03
+ .byte 0xad
+ .byte 0x19
+ .byte 0x9b
+ .byte 0xfa
+ .byte 0x21
+ .byte 0x80
+ .byte 0x26
+ .byte 0xd0
+ .byte 0xf1
+ .byte 0xbe
+ .byte 0x37
+ .byte 0x41
+ .byte 0x65
+ .byte 0xa1
+ .byte 0x6d
+ .byte 0x17 /* Offset to source code. */
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x04
+ .byte 0x00
+ .byte 0x00
+ .byte 0x09
+ .byte 0x02
+ .byte 0x10
+ .byte 0x11
+ .byte 0x40
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x00
+ .byte 0x01
+ .byte 0x05
+ .byte 0x05
+ .byte 0x0a
+ .byte 0xad
+ .byte 0x06
+ .byte 0x0b
+ .byte 0x2e
+ .byte 0x02
+ .byte 0x02
+ .byte 0x00
+ .byte 0x01
+ .byte 0x01
diff --git a/binutils/testsuite/binutils-all/dwarf-embedded-source.rawline b/binutils/testsuite/binutils-all/dwarf-embedded-source.rawline
new file mode 100644
index 00000000..eb49dc55
--- /dev/null
+++ b/binutils/testsuite/binutils-all/dwarf-embedded-source.rawline
@@ -0,0 +1,13 @@
+#...
+ The Directory Table \(offset 0x22, lines 1, columns 1\):
+
+ Entry Name
+ 0 \(indirect line string, offset: 0\): \/path\/to\/code\/
+
+ The File Name Table \(offset 0x31, lines 1, columns 4\):
+ Entry Dir MD5 Name
+ 0 0 0x6da1654137bef1d0268021fa9b19ad03 \(indirect line string, offset: 0xf\): small.c
+ Source: \(indirect line string, offset: 0x17\): int main\(\) {
+ return 0;
+}
+#pass
diff --git a/binutils/testsuite/binutils-all/objdump.exp b/binutils/testsuite/binutils-all/objdump.exp
index 1bb8f55d..af0c63a8 100644
--- a/binutils/testsuite/binutils-all/objdump.exp
+++ b/binutils/testsuite/binutils-all/objdump.exp
@@ -615,6 +615,30 @@ if { ![is_elf_format] } then {
file_on_host delete $output
}
+# Test objdump --debug=rawline on a file containing dwarf-5 embedded source
+
+if { ![is_elf_format] } then {
+ unsupported "objdump --debug=rawline-embedded-source test"
+} elseif { ![binutils_assemble $srcdir/$subdir/dwarf-embedded-source.S tmpdir/dwarf-embedded-source.${obj}] } then {
+ fail "objdump --debug=rawline-embedded-source test"
+} else {
+ if [is_remote host] {
+ set op_testfile [remote_download host tmpdir/dwarf-embedded-source.${obj}]
+ } else {
+ set op_testfile tmpdir/dwarf-embedded-source.${obj}
+ }
+
+ set got [remote_exec host "$OBJDUMP $OBJDUMPFLAGS --dwarf=rawline $op_testfile" "" "/dev/null" "tmpdir/objdump.out"]
+
+ if { [regexp_diff tmpdir/objdump.out $srcdir/$subdir/dwarf-embedded-source.rawline] } then {
+ fail "objdump --debug=rawline-embedded-source test"
+ } else {
+ pass "objdump --debug=rawline-embedded-source test"
+ }
+
+ file_on_host delete $output
+}
+
proc test_build_id_debuglink {option} {
global srcdir
global subdir
diff --git a/include/dwarf2.h b/include/dwarf2.h
index bf9287f1..ba3279f3 100644
--- a/include/dwarf2.h
+++ b/include/dwarf2.h
@@ -293,7 +293,9 @@ enum dwarf_line_number_content_type
DW_LNCT_timestamp = 0x3,
DW_LNCT_size = 0x4,
DW_LNCT_MD5 = 0x5,
+ DW_LNCT_source = 0x6,
DW_LNCT_lo_user = 0x2000,
+ DW_LNCT_LLVM_source = 0x2001,
DW_LNCT_hi_user = 0x3fff
};
--
2.49.0
More information about the Binutils
mailing list