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

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

Commit Message

Will Hawkins May 8, 2026, 11:28 a.m. UTC
  Signed-off-by: Will Hawkins <hawkinsw@obs.cr>
---
 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   |  2 +
 include/dwarf2.h                              |  2 +
 5 files changed, 128 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
  

Comments

Jan Beulich May 15, 2026, 11:52 a.m. UTC | #1
On 08.05.2026 13:28, Will Hawkins wrote:
> Signed-off-by: Will Hawkins <hawkinsw@obs.cr>
> ---
>  v4:
>     Fixed formatting
>     Fixed namesourcepass scoping
>     Updated comments
>     Greatly simplified/commented test case

Much appreciated, as it's much more readable now. Just one other nit below,
apart from my previously voiced more general concern towards the two new
enumerators.

> @@ -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

While functionally correct, preferably || in something dealing with any
yielding boolean. (Likely can be adjusted by whoever ends up committing
this, assuming there'll be someone to approve it despite my concern.)

Jan
  
Will Hawkins May 15, 2026, 4:07 p.m. UTC | #2
On Fri, May 15, 2026 at 7:52 AM Jan Beulich <jbeulich@suse.com> wrote:
>
> On 08.05.2026 13:28, Will Hawkins wrote:
> > Signed-off-by: Will Hawkins <hawkinsw@obs.cr>
> > ---
> >  v4:
> >     Fixed formatting
> >     Fixed namesourcepass scoping
> >     Updated comments
> >     Greatly simplified/commented test case
>
> Much appreciated, as it's much more readable now. Just one other nit below,
> apart from my previously voiced more general concern towards the two new
> enumerators.

I agree -- I appreciate you pushing me to clean it up! I learned a ton
in the process.

>
> > @@ -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
>
> While functionally correct, preferably || in something dealing with any
> yielding boolean. (Likely can be adjusted by whoever ends up committing
> this, assuming there'll be someone to approve it despite my concern.)

Will clean that up, thank you! Also, I have a small tweak to the test
case to make it pass on multiple architectures. Expect a v5 soon!

Thank you, again, for the feedback!
Will


>
> Jan
  

Patch

diff --git a/binutils/dwarf.c b/binutils/dwarf.c
index fa8dce25..1e04b01c 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..b26a55b1
--- /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,"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:
+	.long	0x39                            /* prologue header length */
+	.value  0x5                             /* dwarf version */
+
+	.byte	0x08                            /* address size */
+	.byte	0x00                            /* segment selector */
+
+	.long	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 */
+	.long	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 */
+	.long	0x0f                            /* offset of path string */
+	.byte	0x00                            /* directory index */
+	.long	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..d33b9f8d 100644
--- a/binutils/testsuite/binutils-all/objdump.exp
+++ b/binutils/testsuite/binutils-all/objdump.exp
@@ -615,6 +615,8 @@  if { ![is_elf_format] } then {
     file_on_host delete $output
 }
 
+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
   };