Extract detailed symbol information (struct members) from elf file compiled with ARM-GCC

14,490

Solution 1

You should be able to ask GDB to print this info for you, e.g.

gdb -q a.out
(gdb) ptype PI_REG

Solution 2

is pahole what you need? it can dump variable structure with size and offset.

pahole −−reorganize −C foo xxx.out

struct foo {
int a; / 0 4 /
char c[4]; / 4 4 /
void b; / 8 8 /
long g; / 16 8 /
}; / size: 24, cachelines: 1 /
/ last cacheline: 24 bytes /
/ saved 8 bytes! /

Solution 3

You can use eclipse CDT's gdb mi interface to programatically get this information.

private def loadElfFile(String elfFilePath) {
    var plugin = new MIPlugin

    var file = new File(elfFilePath)

    var cmdFactory = new CommandFactory("mi2")
    session = plugin.createSession(
        MISession::PROGRAM,
        'gdb',
        cmdFactory,
        file,
        #[],
        true,
        new NullProgressMonitor
    )
}

There you can query global variables and their types. Addresses are stored in the hexAddress property of values.

The problem with this approach is its slowness. A struct with 50 members takes almost 10 seconds to process. Querying all structs would take minutes. For IDE tool use cases (like a model transformation) this is impractical. You have to deep dive to elf and dwarf.

Share:
14,490
innout
Author by

innout

Updated on July 26, 2022

Comments

  • innout
    innout almost 2 years

    I’m using ARM-GCC 4.7.4 to compile Code for a Cortex-M4. For our Debug tool I need knowledge about names, types and addresses of all variables in human readable format (e.g. .txt). The map file provides most of the information, unfortunately not for structure contents like below:

    typedef struct {    float32_t   Ref;        // Input:   Reference Value
                float32_t   Fdb;        // Variable:    Feedback Value
                float32_t   Err;        // Input:   Control Error
                float32_t   Kp;     // Parameter:   Gain of the Proportional Part
                float32_t   Up;         // Output:  Output of Proportional Part
                float32_t   Ki;     // Parameter:   Gain of the Integral Part
                float32_t   Ui;     // Output:  Output of the Integral Part
                float32_t   OutPreSat;  // Output:  Not saturated Output
                float32_t   OutMax;     // Parameter:   Maximum Output
                float32_t   OutMin;     // Parameter:   Minimum Output
                float32_t   Out;        // Output:  Saturated Output
            } PI_REG;
    
     PI_REG BU_Uctrl_Udc_PI_Reg = BU_UCTRL_UDC_PI_REG_INIT;
    

    Therefore I tried the tools nm, readelf and objdump to get something out of the .elf file which is compiled with parameter –g3 in dwarf-2 format. Only with objdump I could find the information I searched for:

    objdump –Wi myfile.elf >symbols.txt
    

    The following information about the typedef PI_REG can be found in symbols.txt file:

     <1><38883>: Abbrev Number: 2 (DW_TAG_base_type)
        <38884>   DW_AT_byte_size   : 4
        <38885>   DW_AT_encoding    : 4 (float)
        <38886>   DW_AT_name        : (indirect string, offset: 0x2c63e): float 
     <1><38891>: Abbrev Number: 11 (DW_TAG_typedef)
        <38892>   DW_AT_name        : (indirect string, offset: 0xb336d): float32_t
        <38896>   DW_AT_decl_file   : 4 
        <38897>   DW_AT_decl_line   : 370   
        <38899>   DW_AT_type        : <0x38883>
     <1><390d7>: Abbrev Number: 14 (DW_TAG_structure_type)
        <390d8>   DW_AT_byte_size   : 44    
        <390d9>   DW_AT_decl_file   : 6 
        <390da>   DW_AT_decl_line   : 26    
        <390db>   DW_AT_sibling     : <0x39176> 
     <2><390df>: Abbrev Number: 16 (DW_TAG_member)
        <390e0>   DW_AT_name        : Ref   
        <390e4>   DW_AT_decl_file   : 6 
        <390e5>   DW_AT_decl_line   : 26    
        <390e6>   DW_AT_type        : <0x38891> 
        <390ea>   DW_AT_data_member_location: 2 byte block: 23 0 (DW_OP_plus_uconst: 0) 
     <2><390ed>: Abbrev Number: 16 (DW_TAG_member)
        <390ee>   DW_AT_name        : Fdb   
        <390f2>   DW_AT_decl_file   : 6 
        <390f3>   DW_AT_decl_line   : 27    
        <390f4>   DW_AT_type        : <0x38891> 
        <390f8>   DW_AT_data_member_location: 2 byte block: 23 4 (DW_OP_plus_uconst: 4)
    

    [left out structure members with offsets 6-32]

     <2><39159>: Abbrev Number: 15 (DW_TAG_member)
        <3915a>   DW_AT_name        : (indirect string, offset: 0xc1d9a): OutMin    
        <3915e>   DW_AT_decl_file   : 6 
        <3915f>   DW_AT_decl_line   : 35    
        <39160>   DW_AT_type        : <0x38891>
        <39164>   DW_AT_data_member_location: 2 byte block: 23 24 (DW_OP_plus_uconst: 36) 
     <2><39167>: Abbrev Number: 16 (DW_TAG_member)
        <39168>   DW_AT_name        : Out   
        <3916c>   DW_AT_decl_file   : 6 
        <3916d>   DW_AT_decl_line   : 36    
        <3916e>   DW_AT_type        : <0x38891>
        <39172>   DW_AT_data_member_location: 2 byte block: 23 28 (DW_OP_plus_uconst: 40) 
     <1><39176>: Abbrev Number: 3 (DW_TAG_typedef)
        <39177>   DW_AT_name        : (indirect string, offset: 0xc00d0): PI_REG    
        <3917b>   DW_AT_decl_file   : 6 
        <3917c>   DW_AT_decl_line   : 37    
        <3917d>   DW_AT_type        : <0x390d7> 
    
     <1><3c348>: Abbrev Number: 29 (DW_TAG_variable)
        <3c349>   DW_AT_name        : (indirect string, offset: 0xc3ece): BU_Uctrl_Udc_PI_Reg
        <3c34d>   DW_AT_decl_file   : 1 
        <3c34e>   DW_AT_decl_line   : 40    
        <3c34f>   DW_AT_type        : <0x39176> 
        <3c353>   DW_AT_external    : 1 
        <3c354>   DW_AT_location    : 5 byte block: 3 fc 67 0 20 (DW_OP_addr: 200067fc)
    

    If I want to get information about variables, e.g. the structure BU_Uctrl_Udc_PI_Reg, I have to do the following:

    Find an entry called “DW_TAG_variable” and gather following information:
    ------------------------------------------------------------------------
     - DW_AT_name: The name is BU_Uctrl_Udc_PI_Reg
     - DW_OP_addr: Base address is 200067fc
     - DW_AT_type: The data type can be found at line 39176 
    
    Search line 39176 and gather following information:
    -----------------------------------------------------
     - It is a typedef (DW_TAG_typedef)
     - DW_AT_name: The typedef name is PI_REG
     - DW_AT_type: The definition can be found at line 390d7
    
    Search line 390d7 and gather following information:
    ---------------------------------------------------
     - It is a structure (DW_TAG_structure_type) 
     - DW_AT_byte_size: It is 44 bytes wide
    
    Search the structure Members in upcoming lines until 44 bytes are reached:
    --------------------------------------------------------
    
    1. Member (DW_TAG_member):
     - DW_AT_name: Ref
     - DW_AT_data_member_location: 200067fc + 0
     - DW_AT_type: The data type can be found at line 38891:
     - DW_TAG_typedef: float32_t
     - DW_AT_type: The data type can be found at line 38883: 
     - DW_TAG_base_type: float
     - DW_AT_byte_size: 4 bytes
    
    2. Member (DW_TAG_member):
     - DW_AT_name: Fdb
     - DW_AT_data_member_location: 200067fc + 4
     - DW_AT_type: The data type can be found at line 38891:
     - DW_TAG_typedef: float32_t
     - DW_AT_type: The data type can be found at line 38883:
     - DW_TAG_base_type: float
     - DW_AT_byte_size: 4 bytes
    
    [left out Members 3-9]
    
    10. Member (DW_TAG_member):
     - DW_AT_name: OutMin
     - DW_AT_data_member_location: 200067fc + 36
     - DW_AT_type: The data type can be found at line 38891:
     - DW_TAG_typedef: float32_t
     - DW_AT_type: The data type can be found at line 38883:
     - DW_TAG_base_type: float
     - DW_AT_byte_size: 4 bytes
    
     11. Member (DW_TAG_member):
     - DW_AT_name: Out
     - DW_AT_data_member_location: 200067fc + 40
     - DW_AT_type: The data type can be found at line 38891:
     - DW_TAG_typedef: float32_t
     - DW_AT_type: The data type can be found at line 38883:
     - DW_TAG_base_type: float
     - DW_AT_byte_size: 4 bytes
    

    Frankly speaking, a script file, which automatically gathers the information as above mentioned, would be more complex than my application. Additionally I have to admit that I not really know how I could write such a script. Is there a more easy way to get this type of information? Is there maybe some parameter for the objdump which would help me with that, although I think I tried all the relevant ones? Or does a tool exist which is able to do this? In the end I need a table like this (additionally it would be nice to have all the enums which of course can also be found within the .elf file):

    0x200067fc  float   BU_Uctrl_Udc_PI_Reg.Ref
    0x20006800  float   BU_Uctrl_Udc_PI_Reg.Fdb
    […]
    0x20006832  float   BU_Uctrl_Udc_PI_Reg.OutMin
    0x20006836  float   BU_Uctrl_Udc_PI_Reg.Out
    

    The tool Fromelf http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0477c/index.html (included in Keil µVision) with the parameter --text exactly delivers such a table, but unfortunately I can’t use this because it supposedly needs the .elf or in this case called .axf files compiled with Arm Compiler Toolchain to work. Additionally there are license issues.

    Thanks for any hints.