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

Message ID 20260516001043.422461-1-hawkinsw@obs.cr
State New
Headers
Series [v5] 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 success Test passed
linaro-tcwg-bot/tcwg_binutils_check--master-arm fail Test failed

Commit Message

Will Hawkins May 16, 2026, 12:10 a.m. UTC
  Signed-off-by: Will Hawkins <hawkinsw@obs.cr>
---
 v5:
    Fixed bitwise or vs. logical or
    Made test case cross platform compatible
 v4:
    Fixed formatting
    Fixed namesourcepass scoping
    Updated comments
    Greatly simplified/commented test case
 v3: Fixed failing test on aarch64
 v2: 
    Fixed variable scoping
    Fixed name of line number header entry
    Added test

 binutils/dwarf.c                              | 33 ++++++--
 .../binutils-all/dw5-embedded-source.S        | 78 +++++++++++++++++++
 .../binutils-all/dw5-embedded-source.d        | 18 +++++
 binutils/testsuite/binutils-all/objdump.exp   |  4 +
 include/dwarf2.h                              |  2 +
 5 files changed, 130 insertions(+), 5 deletions(-)
 create mode 100644 binutils/testsuite/binutils-all/dw5-embedded-source.S
 create mode 100644 binutils/testsuite/binutils-all/dw5-embedded-source.d
  

Patch

diff --git a/binutils/dwarf.c b/binutils/dwarf.c
index fa8dce25..1d74823a 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:
+		/* Source is displayed on next line and not in a column.  */
+		break;
 	      default:
 		printf (_("\t(Unknown format content type %" PRIu64 ")"),
 			content_type);
@@ -5861,8 +5865,8 @@  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 for better screen layout.  */
+      for (int namesourcepass = 0; namesourcepass < 3; namesourcepass++)
 	{
 	  format = format_start;
 	  data = datapass;
@@ -5872,13 +5876,32 @@  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))
+			    || ((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/dw5-embedded-source.S b/binutils/testsuite/binutils-all/dw5-embedded-source.S
new file mode 100644
index 00000000..6a495dee
--- /dev/null
+++ b/binutils/testsuite/binutils-all/dw5-embedded-source.S
@@ -0,0 +1,78 @@ 
+	.text
+	.p2align	4, 0x90
+	.globl	main
+	.type	main, %function
+main:
+	.size	main, .-main
+	.section	.debug_line_str,"",%progbits
+.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
+	.4byte	.Ldebug_addr_end0-.Ldebug_addr_start0 /* Length of contribution */
+.Ldebug_addr_start0:
+	.2byte	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:
+	.4byte	0x39                            /* prologue header length */
+	.2byte  0x5                             /* dwarf version */
+
+	.byte	0x08                            /* address size */
+	.byte	0x00                            /* segment selector */
+
+	.4byte	0x3E                            /* header length = 62 */
+
+	.byte	0x01                            /* min instruction length = 1 */
+	.byte	0x01                            /* max ops per instruction = 1 */
+	.byte	0x01                            /* default is statement */
+	.byte	0xfb                            /* line base */
+	.byte	0x0e                            /* line range = 14 */
+	.byte	0x0d                            /* opcode base = 13 */
+
+	.byte	0x00                            /* operand counts for standard opcodes */
+	.byte	0x01
+	.byte	0x01
+	.byte	0x01
+	.byte	0x01
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x01
+	.byte	0x00
+	.byte	0x00
+	.byte	0x01
+
+	.byte	0x01                            /* directory entry format count = 1 */
+	.uleb128 0x01                           /* the path ... */
+	.uleb128 0x1f                           /* is a DW_FORM_line_strp */
+
+	.byte	0x01                            /* directories count = 1 */
+	.4byte	0x00                            /* offset of path string */
+
+	.byte	0x03                            /* file entry format count = 3 */
+	.uleb128 0x01                           /* the path ... */
+	.uleb128 0x1f                           /* is a DW_FORM_line_strp */
+	.uleb128 0x02                           /* the directory index ... */
+	.uleb128 0x0f                           /* is a DW_FORM_udata */
+	.uleb128 0x2001                         /* the source ... */
+	.uleb128 0x1f                           /* is a DW_FORM_line_strp */
+
+	.byte	0x01                            /* file names count = 1 */
+	.4byte	0x0f                            /* offset of path string */
+	.byte	0x00                            /* directory index */
+	.4byte	0x17                            /* offset of source code */
+
+	.byte	0x04                            /* set file index to 0 */
+	.uleb128 0x0
+
+	.byte	0x00                            /* end sequence */
+	.byte	0x01
+	.byte	0x01
diff --git a/binutils/testsuite/binutils-all/dw5-embedded-source.d b/binutils/testsuite/binutils-all/dw5-embedded-source.d
new file mode 100644
index 00000000..786ea1ff
--- /dev/null
+++ b/binutils/testsuite/binutils-all/dw5-embedded-source.d
@@ -0,0 +1,18 @@ 
+#objdump: --dwarf=rawline
+#name: objdump (objdump --dwarf=rawline with embedded source)
+#source: dw5-embedded-source.S
+# Nicely print embedded source when displaying the line program in raw format
+
+#...
+ 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 0x2f, lines 1, columns 3\):
+  Entry	Dir	Name
+  0	0	\(indirect line string, offset: 0xf\): small.c
+  Source: \(indirect line string, offset: 0x17\): int main\(\) {
+  return 0;
+}
+#...
diff --git a/binutils/testsuite/binutils-all/objdump.exp b/binutils/testsuite/binutils-all/objdump.exp
index 1bb8f55d..818674c2 100644
--- a/binutils/testsuite/binutils-all/objdump.exp
+++ b/binutils/testsuite/binutils-all/objdump.exp
@@ -615,6 +615,10 @@  if { ![is_elf_format] } then {
     file_on_host delete $output
 }
 
+if { [is_elf_format] } then {
+    run_dump_test dw5-embedded-source
+}
+
 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
   };