[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: DWARF5 line number program header
From: |
Martin Cermak |
Subject: |
Re: DWARF5 line number program header |
Date: |
Fri, 27 Oct 2023 10:50:07 +0200 |
On Fri 2023-10-27 10:43 , Martin Cermak wrote:
> Hi folks, I have a question.
>
> I'm wondering how to cover the DWARF5 line number program header
> using the Poke language. My motivation is to reuse my dirty poke
> code that really helped me at some point, into a generally reusable
> pickle covering the .debug_line ELF section.
>
> The header is described in DWARF5 standard, section 6.2.4 and
> sits at the beginning of the .debug_line ELF section. There is
> also a line number program in this section, following the header,
> but we don't care for now :)
>
> I've been playing with one specific ELF file, and created following
> dirty Poke struct (saved it into dwarf-line.pk):
>
> > 1 type directory_entry_format_t =
> > 2 struct
> > 3 {
> > 4 ULEB128 content_type;
> > 5 ULEB128 form_code;
> > 6 };
> > 7
> > 8 type file_name_entry_format_t =
> > 9 struct
> > 10 {
> > 11 ULEB128 content_type;
> > 12 ULEB128 form_code;
> > 13 };
> > 14
> > 15
> > 16
> > 17
> > 18 type debug_line_sec_hdr =
> > 19 struct
> > 20 {
> > 21 uint<32> unit_length; // offset: 0, size: 4 value: 85
> > 22 uint<16> version : version == 5; // offset: 4, size: 2 value: 5
> > 23 uint<8> address_size ; // offset: 6, size: 1 value: 8
> > 24 uint<8> segment_selector_size; // offset: 7, size: 1 value: 0
> > 25 uint<32> header_length; // offset: 8, size: 4 value: 42
> > 26 uint<8> minimum_instruction_length; // offset: 12, size: 1 value: 1
> > 27 uint<8> maximum_operations_per_instruction; // offset: 13, size: 1
> > value: 1
> > 28 uint<8> default_is_stmt; // offset: 14, size: 1 value: 1
> > 29 int<8> line_base; // offset: 15, size: 1 value: -5
> > 30 uint<8> line_range; // offset: 16, size: 1 value: 14
> > 31 uint<8> opcode_base; // offset: 17, size: 1 value: 13
> > 32 uint<8>[opcode_base - 1] standard_opcode_lengths; // offset: 18,
> > size: 12 * 1
> > 33 uint<8> directory_entry_format_count; // offset: 30, size: 1 value:
> > 1
> > 34 directory_entry_format_t[directory_entry_format_count]
> > directory_entry_format; // offset: 31, size: 2
> > 35 // DW_LNCT_path = 0x1
> > 36 // DW_FORM_line_strp = 0x1f
> > 37 ULEB128 directories_count; // offset: 33, size: 1 value: 1
> > 38 uint<32> DIRS;
> > 39 uint<8> file_name_entry_format_count; // offset: 38, size: 1 value:
> > 2
> > 40 file_name_entry_format_t[file_name_entry_format_count]
> > file_name_entry_format; // offset: 39, size: 4
> > 41 // DW_LNCT_path = 0x1
> > 42 // DW_FORM_line_strp = 0x1f
> > 43 // DW_LNCT_directory_index = 0x2
> > 44 // DW_FORM_udata = 0x0f
> > 45 ULEB128 file_names_count; // offset: 43, size: 1 value: 2
> > 46 uint<32> FILES;
> > 47 };
>
> I've used it like this:
>
> > $ cat test.c
> > int main()
> > {
> > return 0;
> > }
> > $ gcc -gdwarf-5 -g test.c
> > $ poke a.out
> > (poke) load elf
> > (poke) load dwarf
> > (poke) load leb128
> > (poke) var elf = Elf64_File @ 0#B
> > (poke) var debug_line_sec = elf.get_sections_by_name (".debug_line")[0];
> > (poke) load "dwarf-line.pk"
> > (poke) var lh = debug_line_sec_hdr @ debug_line_sec.sh_offset;
> > (poke) lh
> > debug_line_sec_hdr {
> > unit_length=75U,
> > version=5UH,
> > address_size=8UB,
> > segment_selector_size=0UB,
> > header_length=42U,
> > minimum_instruction_length=1UB,
> > maximum_operations_per_instruction=1UB,
> > default_is_stmt=1UB,
> > line_base=-5B,
> > line_range=14UB,
> > opcode_base=13UB,
> > standard_opcode_lengths=[0UB,1UB,1UB,1UB,1UB,0UB,0UB,0UB,1UB,0UB,0UB,1UB],
> > directory_entry_format_count=1UB,
> > directory_entry_format=[directory_entry_format_t {
> > content_type=#<uleb128:1>,
> > form_code=#<uleb128:31>
> > }],
> > directories_count=#<uleb128:1>,
> > DIRS=0U,
> > file_name_entry_format_count=2UB,
> > file_name_entry_format=[file_name_entry_format_t {
> > content_type=#<uleb128:1>,
> > form_code=#<uleb128:31>
> > },file_name_entry_format_t {
> > content_type=#<uleb128:2>,
> > form_code=#<uleb128:15>
> > }],
> > file_names_count=#<uleb128:2>,
> > FILES=39U
> > }
> > (poke)
>
> This works fine for this specific ELF file, but to turn it into a
> generally reusable pickle, one needs to solve the following
> problem. Looking at the struct above, things are fine till line
> 38 which declares DIRS. The problem is that it's only uint<32>
> in my specific case, but in general, lines 33, 34 and 37 together
> say, that DIRS is one record that needs to be interpreted as
> DW_LNCT_path and it is a pointer to a string table DW_FORM_line_strp.
>
> IOW, lines 33, 34 and 37 together define how DIRS actually look
> like. So, the declarative description lines 21-->37 is nice,
> but the challenge starts on line 38, because DIRS isn't really as
> simple as uint<32> (This uint<32> is just right to set the offset
> for the following item on line 39 right, but it's a hack.)
>
> Similar problem happens once more later in this header, with
> FILES, that's line 46.
>
> I'm wondering how to cover DIRS and FILES with proper Poke-speak :)
Let me add, that elfutil's readelf.c interprets DIRS and FILES
using print_form_data() see [1]. It's easy to do with imperative
language, but I'm wondering how to do this using Poke :)
Any thoughts, please?
Martin
-------
[1] https://sourceware.org/git/?p=elfutils.git;a=blob;f=src/readelf.c#l8709