ローカル変数の一覧を取得
Posted feedbacks - C
C 言語の場合ローカル変数名はデバッグ情報にしか含まれませんので gcc の -g オプションが必須です。 デバッグ情報を得るために libelf, libdwarf と、ハッシュテーブルを使うために glib を使用しました。 コンパイルこんな感じです。 % gcc -g `pkg-config glib --cflags` locals.c -o locals `pkg-config glib --libs` -lelf -ldwarf 実行結果 % ./locals x=hello y=1 スタックフレームにある変数を得るのに複数の種類の型が混在していると厄介だったのでローカル変数は文字列(char*)のみとなってしまいました。 あと、X86 32bit 環境でしか動作しないと思います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <libelf.h>
#include <libdwarf/libdwarf.h>
#include <libdwarf/dwarf.h>
#include <glib.h>
GHashTable *locals();
GHashTable *foo(){
char *x = "1";
char *y = "hello";
return locals();
}
GHashTable *locals(){
GHashTable *hash;
int fd;
Elf *elf;
int ret;
Dwarf_Debug dbg;
Dwarf_Die cu_die;
Dwarf_Die func_die;
Dwarf_Die var_die;
Dwarf_Die var_die_tmp;
Dwarf_Error err;
Dwarf_Unsigned cu_header_length = 0;
Dwarf_Unsigned abbrev_offset = 0;
Dwarf_Half version_stamp = 0;
Dwarf_Half address_size = 0;
Dwarf_Unsigned next_cu_offset = 0;
Dwarf_Half tag;
Dwarf_Attribute attr;
char *name;
Dwarf_Addr high_pc;
Dwarf_Addr low_pc;
int i;
void *frame = __builtin_frame_address(1);
unsigned long retaddr = (unsigned long)__builtin_return_address(0);
hash = g_hash_table_new((GHashFunc)g_str_hash, (GCompareFunc)g_str_equal);
elf_version(EV_CURRENT);
fd = open("/proc/self/exe", O_RDONLY);
elf = elf_begin(fd, ELF_C_READ, (Elf*)0);
ret = dwarf_elf_init(elf, DW_DLC_READ, NULL, NULL, &dbg, &err);
while ((ret = dwarf_next_cu_header(
dbg, &cu_header_length, &version_stamp, &abbrev_offset,
&address_size, &next_cu_offset, &err)) == DW_DLV_OK){
cu_die = NULL;
while(dwarf_siblingof(dbg, cu_die, &cu_die, &err) != DW_DLV_NO_ENTRY){
dwarf_tag(cu_die, &tag, &err);
if(tag != DW_TAG_compile_unit) continue;
ret = dwarf_child(cu_die, &func_die, &err);
if(ret != DW_DLV_OK) continue;
do{
dwarf_tag(func_die, &tag, &err);
if(tag != DW_TAG_subprogram) continue;
dwarf_attr(func_die, DW_AT_high_pc, &attr, &err);
dwarf_formaddr(attr, &high_pc, &err);
dwarf_attr(func_die, DW_AT_low_pc, &attr, &err);
dwarf_formaddr(attr, &low_pc, &err);
if(low_pc > retaddr || retaddr > high_pc) continue;
ret = dwarf_child(func_die, &var_die, &err);
if(ret != DW_DLV_OK) continue;
i=0;
var_die_tmp = var_die;
while(dwarf_siblingof(dbg, var_die, &var_die, &err) != DW_DLV_NO_ENTRY) i++;
var_die = var_die_tmp;
do{
dwarf_tag(var_die, &tag, &err);
if(tag != DW_TAG_variable) continue;
dwarf_attr(var_die, DW_AT_name, &attr, &err);
dwarf_formstring(attr, &name, &err);
g_hash_table_insert(hash, strdup(name),
strdup((frame - 4 - (4 * i--))));
}while(dwarf_siblingof(dbg, var_die, &var_die, &err) != DW_DLV_NO_ENTRY);
}while(dwarf_siblingof(dbg, func_die, &func_die, &err) != DW_DLV_NO_ENTRY);
}
}
dwarf_finish(dbg, &err);
elf_end(elf);
close(fd);
return hash;
}
int main(int argc, char *argv[]){
GHashTable *hash = foo();
printf("x=%s\n", *(char**)g_hash_table_lookup(hash, "x"));
printf("y=%s\n", *(char**)g_hash_table_lookup(hash, "y"));
g_hash_table_destroy(hash);
return EXIT_SUCCESS;
}
|



にしお
#3391()
Rating0/0=0.00
Pythonで表現すると、下のコードの???部分を埋めることになります。
>>> def foo(): x = 1 y = "hello" ??? return result >>> foo() {'y': 'hello', 'x': 1}[ reply ]