[v3] binutils/dwarf: Print embedded source, when available
Commit Message
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
Comments
On 4/21/2026 4:02 AM, Will Hawkins wrote:
> 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
Hello Will, it would be helpful if you could keep the original commit
message from v1 of your patch (except for the last two paragraphs),
including the description and motivation, and place any additional
comments below the three dashes (as you did with the patch changelog).
This should make it easier for everyone to clearly see what is intended
to be committed without needing to dig through previous patch versions.
>
> 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
Thanks and regards,
Jens
On 21.04.2026 04:02, Will Hawkins wrote:
> v3 should contain a test that passes on aarch64 as well as x86_64. Sorry
> for the hassle!
What about other targets, including 32-bit ones?
> --- 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;
Just keep recorded that I'm concerned of such unqualified uses of constants
from custom ranges (LLVM in this case).
> @@ -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++)
for (unsigned int namesourcepass = 0; namesourcepass < 3; namesourcepass++)
(suitably line wrapped if necessary)
> @@ -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);
Indentation is better now that it (iirc) was in v1, but it's still not
quite right. Binary operators wrapped to the next line want to align
with the corresponding part of the expression on the earlier line. At
the example ...
> + 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))
... here:
if (namesourcepass == 2
&& (content_type == DW_LNCT_LLVM_source
|| content_type == DW_LNCT_source))
> --- /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:
Up to here the comments allow to reasonably follow what is there.
> + .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
The same cannot be said here, which makes this pretty hard to maintain (i.e.
change if need be). Question is anyway - do we really need to resort to
.byte to express what's wanted?
> --- /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;
> +}
The figure braces would better also be escaped, I think.
> --- 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
> +}
Is all of this necessary? Can't the test be done via a simple run_dump_test?
> --- 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,
This isn't official yet aiui, so may want annotating accordingly.
More generally, Nick - what's the policy towards use of constants from not
yet released specifications (which hence may still change)?
Jan
> DW_LNCT_lo_user = 0x2000,
> + DW_LNCT_LLVM_source = 0x2001,
> DW_LNCT_hi_user = 0x3fff
> };
>
Thank you for taking the time to give feedback!
On Tue, Apr 21, 2026 at 12:03 PM Jan Beulich <jbeulich@suse.com> wrote:
>
> On 21.04.2026 04:02, Will Hawkins wrote:
> > v3 should contain a test that passes on aarch64 as well as x86_64. Sorry
> > for the hassle!
>
> What about other targets, including 32-bit ones?
I, unfortunately, have not tested on that target, yet.
>
> > --- 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;
>
> Just keep recorded that I'm concerned of such unqualified uses of constants
> from custom ranges (LLVM in this case).
Ack. I am absolutely not unconcerned ... just trying to help make
objdump even more of a great tool than it is!
>
> > @@ -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++)
>
> for (unsigned int namesourcepass = 0; namesourcepass < 3; namesourcepass++)
>
> (suitably line wrapped if necessary)
I surely would have written it the way that you suggested. However,
when I looked through existing code, I did not see any formatted this
way. I assumed that was because of an interest in maintaining
compatibility with C89. I will absolutely make the update, of course,
but I just wanted to make sure you knew that I was trying my best to
follow the project's standards.
>
> > @@ -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);
>
> Indentation is better now that it (iirc) was in v1, but it's still not
> quite right. Binary operators wrapped to the next line want to align
> with the corresponding part of the expression on the earlier line. At
> the example ...
I will gladly fix! I was also wondering: These expressions are hard to
grok. I found the meaning hard to identify even in the existing code.
With the additional elements, it now seems like it might be a good
idea to expand into an if statement? I'd love feedback!
>
> > + 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))
>
> ... here:
>
> if (namesourcepass == 2
> && (content_type == DW_LNCT_LLVM_source
> || content_type == DW_LNCT_source))
>
> > --- /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:
>
> Up to here the comments allow to reasonably follow what is there.
>
> > + .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
>
> The same cannot be said here, which makes this pretty hard to maintain (i.e.
> change if need be). Question is anyway - do we really need to resort to
> .byte to express what's wanted?
I will absolutely update -- your point is very well taken!
>
> > --- /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;
> > +}
>
> The figure braces would better also be escaped, I think.
>
> > --- 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
> > +}
>
> Is all of this necessary? Can't the test be done via a simple run_dump_test?
Good question! I will investigate!
>
> > --- 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,
>
> This isn't official yet aiui, so may want annotating accordingly.
>
> More generally, Nick - what's the policy towards use of constants from not
> yet released specifications (which hence may still change)?
>
> Jan
Thank you, again, for your feedback! If the group decides that there
is no interest in supporting it, I'll be glad to back off!
Will
>
> > DW_LNCT_lo_user = 0x2000,
> > + DW_LNCT_LLVM_source = 0x2001,
> > DW_LNCT_hi_user = 0x3fff
> > };
> >
>
On 22.04.2026 02:26, Will Hawkins wrote:
> On Tue, Apr 21, 2026 at 12:03 PM Jan Beulich <jbeulich@suse.com> wrote:
>> On 21.04.2026 04:02, Will Hawkins wrote:
>>> @@ -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++)
>>
>> for (unsigned int namesourcepass = 0; namesourcepass < 3; namesourcepass++)
>>
>> (suitably line wrapped if necessary)
>
> I surely would have written it the way that you suggested. However,
> when I looked through existing code, I did not see any formatted this
> way. I assumed that was because of an interest in maintaining
> compatibility with C89. I will absolutely make the update, of course,
> but I just wanted to make sure you knew that I was trying my best to
> follow the project's standards.
There may not be examples in this particular file, but after we switched
to C99, examples have appeared in various places of the codebase.
>>> @@ -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);
>>
>> Indentation is better now that it (iirc) was in v1, but it's still not
>> quite right. Binary operators wrapped to the next line want to align
>> with the corresponding part of the expression on the earlier line. At
>> the example ...
>
> I will gladly fix! I was also wondering: These expressions are hard to
> grok. I found the meaning hard to identify even in the existing code.
> With the additional elements, it now seems like it might be a good
> idea to expand into an if statement? I'd love feedback!
Personally I prefer as-is (I'd even go as far as combining decl and
statement into just a decl), but of course this is entirely subjective.
Jan
@@ -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);
}
}
new file mode 100644
@@ -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
new file mode 100644
@@ -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
@@ -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
@@ -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
};