poke-devel
[Top][All Lists]
Advanced

[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



reply via email to

[Prev in Thread] Current Thread [Next in Thread]