Localizando parâmetros de função para funções em bibliotecas de objetos compartilhados

6

Atualmente, estou pesquisando algumas bibliotecas c sem documentação. Eu estou querendo saber se é sempre possível recuperar mais metadados, como parâmetros e valores de retorno, fora do que é fornecido chamando nm -D ou objdump -T filename | grep text . Eu não tenho certeza se isso é possível, mas se é, isso me poupa de caçar quem estava no comando da biblioteca!

Editar: gostaria de poder fazer isso sem ler o código da máquina, se possível. Parece que há algumas soluções que me permitem fazê-lo facilmente se eu fosse um especialista em código de máquina, mas desde que eu não sou e não tenho o desejo atual de pular naquele buraco de coelho, eu realmente estou esperando que haja outro maneira.

    
por Edward Shen 10.12.2013 / 03:20

1 resposta

8

Uma pergunta muito semelhante foi feita no Stack Overflow: Como extrair protótipo de função de um arquivo ELF?

Resumindo: geralmente você não pode. Se o executável (ou biblioteca compartilhada) não tiver informações de depuração, as informações sobre o número e o tipo de argumentos não serão armazenadas no executável.

Se o arquivo de objeto compartilhado tiver informações de depuração, você poderá extrair as informações com readelf -wi ou usando um depurador.

Por exemplo, eu tenho um executável ELF que contém uma função int foo(char a, long b) , compilada com informações de depuração. GDB me diz:

(gdb) p foo
$1 = {int (char, long int)} 0x40051c <foo>

E readelf -wi (um pouco enigmático, você terá que combinar as entradas):

 <1><2d>: Abbrev Number: 2 (DW_TAG_subprogram)            <= function
    <2e>   DW_AT_external    : 1    
    <2f>   DW_AT_name        : foo                        <= func name
    <33>   DW_AT_decl_file   : 1    
    <34>   DW_AT_decl_line   : 1    
    <35>   DW_AT_prototyped  : 1    
    <36>   DW_AT_type        : <0x6c>                     <= return type
    <3a>   DW_AT_low_pc      : 0x40051c 
    <42>   DW_AT_high_pc     : 0x400532 
    <4a>   DW_AT_frame_base  : 0x0  (location list)
    <4e>   DW_AT_GNU_all_call_sites: 1  
    <4f>   DW_AT_sibling     : <0x6c>   
 <2><53>: Abbrev Number: 3 (DW_TAG_formal_parameter)      <= parameter
    <54>   DW_AT_name        : a    
    <56>   DW_AT_decl_file   : 1    
    <57>   DW_AT_decl_line   : 1    
    <58>   DW_AT_type        : <0x73>   
    <5c>   DW_AT_location    : 2 byte block: 91 6c  (DW_OP_fbreg: -20)
 <2><5f>: Abbrev Number: 3 (DW_TAG_formal_parameter)      <= other param
    <60>   DW_AT_name        : b    
    <62>   DW_AT_decl_file   : 1    
    <63>   DW_AT_decl_line   : 1    
    <64>   DW_AT_type        : <0x7a>   
    <68>   DW_AT_location    : 2 byte block: 91 60  (DW_OP_fbreg: -32)
 <1><6c>: Abbrev Number: 4 (DW_TAG_base_type)
    <6d>   DW_AT_byte_size   : 4    
    <6e>   DW_AT_encoding    : 5    (signed)
    <6f>   DW_AT_name        : int  
 <1><73>: Abbrev Number: 5 (DW_TAG_base_type)
    <74>   DW_AT_byte_size   : 1    
    <75>   DW_AT_encoding    : 6    (signed char)
    <76>   DW_AT_name        : (indirect string, offset: 0x2e): char    
 <1><7a>: Abbrev Number: 5 (DW_TAG_base_type)
    <7b>   DW_AT_byte_size   : 8    
    <7c>   DW_AT_encoding    : 5    (signed)
    <7d>   DW_AT_name        : (indirect string, offset: 0x0): long int 

Observe que, para C ++, os símbolos que você vê com nm contêm mais informações (a menos que tenham sido declarados extern "C" - o número e o tipo de parâmetros devem estar disponíveis ao vinculador para lidar com sobrecarga. Mas o tipo de retorno as informações também não estão lá (mas os símbolos são desconfigurados - c++filt pode ser usado para desmanchar).

Compilar o mesmo arquivo de origem que o C ++ fornece a seguinte saída para nm a.out | c++filt :

...
0000000000400554 T foo(char, long)
...
    
por 10.12.2013 / 08:10