Имя переменной, аргументы функции во время выполнения в C
Можно ли узнать аргументы функций и типы имен переменных во время выполнения в C-программе? Например, если у меня есть функция:
int abc(int x, float y , somestruct z ){
char a;
int b ;
}
Могу ли я узнать внутри этой функции abc()
какие имена аргументов и переменных т.е. в этом случае его x
, y
, z
, a
, b
и они имеют тип int
, float
, somestruct
, char
, int
,
Скажите, есть ли другая функция:
float some_func(specialstruct my_struct, int index){
}
Я должен знать, что аргументы name my_struct
, index
и типы specialstruct
, int
,
Мне нужна эта информация во время выполнения?
У меня есть доступ к базовому указателю и адресу возврата, могу ли я получить необходимую информацию, используя указатель выше.
Мне удалось извлечь имя функции, используя адрес возврата и dladdr()
функция.
я вижу GDB
делает это, так что должно быть возможно извлечь эту информацию?
4 ответа
Как уже отмечалось, рефлексия не встроена в язык C или C++. Здесь есть множество идей
Однако в C/C++ возможно отражение с помощью сторонней библиотеки и символов отладки в исполняемом файле или внешнем файле.
dwarfdump
исполняемый более или менее делает то, что вы надеетесь. С помощью DWARF доступны подробные сведения о функции, переменных, типах и т. Д. Аналогичным образом, функциональность libdwarfdump может использоваться процессом для проверки себя.
Вот простой ручной пример:
typedef struct somestruct
{
int i;
int j;
} somestruct ;
int abc(int x, float y , struct somestruct z ){
char a;
int b ;
}
int main(int argc, char* argv[])
{
struct somestruct z;
abc(1,1.0f,z);
return 0;
}
и частичный вывод из dwarfdump
< 1><0x00000055> DW_TAG_subprogram
DW_AT_external yes(1)
DW_AT_name "abc"
DW_AT_decl_file 0x00000001 /tmp/dwarf.c
DW_AT_decl_line 0x00000009
DW_AT_prototyped yes(1)
DW_AT_type <0x0000004e>
DW_AT_low_pc 0x004004ed
DW_AT_high_pc <offset-from-lowpc>18
DW_AT_frame_base len 0x0001: 9c: DW_OP_call_frame_cfa
DW_AT_GNU_all_call_sites yes(1)
DW_AT_sibling <0x000000ad>
< 2><0x00000076> DW_TAG_formal_parameter
DW_AT_name "x"
DW_AT_decl_file 0x00000001 /tmp/dwarf.c
DW_AT_decl_line 0x00000009
DW_AT_type <0x0000004e>
DW_AT_location len 0x0002: 916c: DW_OP_fbreg -20
< 2><0x00000082> DW_TAG_formal_parameter
DW_AT_name "y"
DW_AT_decl_file 0x00000001 /tmp/dwarf.c
DW_AT_decl_line 0x00000009
DW_AT_type <0x000000ad>
DW_AT_location len 0x0002: 9168: DW_OP_fbreg -24
< 2><0x0000008e> DW_TAG_formal_parameter
DW_AT_name "z"
DW_AT_decl_file 0x00000001 /tmp/dwarf.c
DW_AT_decl_line 0x00000009
DW_AT_type <0x0000002d>
DW_AT_location len 0x0002: 9160: DW_OP_fbreg -32
При внимательном изучении мы видим, что фрагмент определяет функцию 'abc' с аргументами x, y и z.
Тип параметра x является косвенной ссылкой на таблицу типов с ключом 0x4e.
Посмотрев в другом месте вывода, мы можем увидеть определение для типа 0x4e. Тип 0x2d - это некоторая структура, которая связана с параметром z.
< 1><0x0000002d> DW_TAG_structure_type
DW_AT_name "somestruct"
DW_AT_byte_size 0x00000008
DW_AT_decl_file 0x00000001 /tmp/dwarf.c
DW_AT_decl_line 0x00000003
DW_AT_sibling <0x0000004e>
< 1><0x0000004e> DW_TAG_base_type
DW_AT_byte_size 0x00000004
DW_AT_encoding DW_ATE_signed
DW_AT_name "int"
Комбинация ptrace, ELF, DWARF и файловой системы /proc позволяет gdb считывать статическую и динамическую информацию для процесса. Другой процесс может использовать аналогичные функции для создания функций отражения.
Я использовал варианты этой стратегии для создания пользовательских отладчиков и детекторов утечки памяти. Однако я никогда не видел, чтобы эта стратегия использовалась для бизнес-логики.
На самом деле нет никакого собственного способа сделать это в C. На других языках то, что вы искали бы, было бы отражением. Вы можете сделать это с помощью макросов и некоторых хитростей, но по базовому принципу вам нужно знать имена переменных и аргументы во время компиляции.
В C. нет отражения или подобных вещей. Если вам нужна такая возможность - вы должны разработать некоторые утилиты, макросы для этой цели и использовать специальные правила кодирования для достижения желаемого эффекта. Но IMO - это не будет читаемый и понятный C-код.
Существует ограниченный способ самоанализа, предоставляемый функциями общей библиотеки dlsym
а также dladdr
предоставление имени по адресу и наоборот перевод. Это, однако, не часть языка Си, а скорее функция, предоставляемая динамическим загрузчиком ОС. Вы можете, однако, не вычесть, например, является ли тот символ, который вы нашли, переменной или функцией.
backtrace
и др. составляют расширение стандарта GNU, которое позволяет анализировать стек вызовов функции (историю вызовов). Если в двоичном коде еще есть символы (имена функций), backtrace_symbols
позволит вам получить их.
__LINE__
а также __FILE__
предопределенные макросы обеспечивают способ создания дампа, где вы находитесь, и могут быть основой некоторых очень полезных макросов для трассировки.
И это все. С не дает больше интроспекции, чем это. Имена и типы параметров исчезают в двоичном формате, сигнатуры функций исчезают, а также типы результатов функций.