[v2] binutils/dwarf: Print embedded source, when available

Message ID 20260420143919.2721336-1-hawkinsw@obs.cr
State New
Headers
Series [v2] binutils/dwarf: Print embedded source, when available |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_binutils_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_binutils_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_binutils_check--master-aarch64 fail Test failed

Commit Message

Will Hawkins April 20, 2026, 2:39 p.m. UTC
  I sincerely appreciate the first round of feedback and hope that I
responded to all the feedback.

I am clearly new to writing tests and hope that my cargo cult-ing is on
the right track.

Hope everyone had a great weekend!
Will

Signed-off-by: Will Hawkins <hawkinsw@obs.cr>
---
 binutils/dwarf.c                              |  34 ++-
 .../binutils-all/dwarf-embedded-source.S      | 257 ++++++++++++++++++
 .../dwarf-embedded-source.rawline             |  13 +
 binutils/testsuite/binutils-all/objdump.exp   |  24 ++
 include/dwarf2.h                              |   2 +
 5 files changed, 325 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
  

Patch

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..0fb87df2
--- /dev/null
+++ b/binutils/testsuite/binutils-all/dwarf-embedded-source.S
@@ -0,0 +1,257 @@ 
+	.text
+	.file	"small.c"
+	.globl	main                            # -- Begin function main
+	.p2align	4, 0x90
+	.type	main,@function
+main:                                   # @main
+.Lfunc_begin0:
+	#.loc	0 1 0                           # small.c:1:0
+	.cfi_startproc
+# %bb.0:
+	pushq	%rbp
+	.cfi_def_cfa_offset 16
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+	.cfi_def_cfa_register %rbp
+	movl	$0, -4(%rbp)
+.Ltmp0:
+	xorl	%eax, %eax
+	popq	%rbp
+	.cfi_def_cfa %rsp, 8
+	retq
+.Ltmp1:
+.Lfunc_end0:
+	.size	main, .Lfunc_end0-main
+	.cfi_endproc
+                                        # -- End function
+	.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	.Lfunc_end0-.Lfunc_begin0       # 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	.Lfunc_end0-.Lfunc_begin0       # 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	.Lfunc_begin0
+.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
   };