A very similar question was asked on Stack Overflow: How to extract function prototype from an ELF file?
In short: generally you can't. If the executable (or shared library) doesn't have debug information, the information on the number and type of arguments is not stored in the executable.
If the shared object file does have debug information, then you should be able to extract the information with readelf -wi
, or by using a debugger.
For example, I've got an ELF executable that contains a function int foo(char a, long b)
, compiled with debug info. GDB tells me:
(gdb) p foo
$1 = {int (char, long int)} 0x40051c <foo>
And readelf -wi
(a bit cryptic, you'll have to match up the entries yourself) has:
<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
Note that for C++, the symbols you see with nm
carry more information (unless they've been declared extern "C"
- the number and type of parameters must be available to the linker to handle overloading. But the return type information isn't there either. (But the symbols are mangled - c++filt
can be used to demangle.)
Compiling the same source file as C++ gives the following output for nm a.out | c++filt
:
...
0000000000400554 T foo(char, long)
...