Linux 进程似乎使用
dlclose
卸载共享库,同时仍将其函数注册为回调。当回调被调用时它稍后崩溃,现在是无效内存,并且 gdb 无法因此展开堆栈。
缺少应用程序在加载时显式存储共享库列表,有没有办法从核心转储中获取已卸载库的加载地址(至少是通过
dlopen
加载的库)?
有没有办法从核心转储中获取已卸载库的加载地址
没有。
core
是崩溃时进程的内存图像,有关已卸载库的信息 不再存在——运行时加载程序没有理由保留该信息。
不过,你可以大概猜到。
假设您的代码如下所示:
void *h = dlopen("somelib.so", ...);
some_struct.callback = (int(*)(void)) dlsym(h, "some_func");
dlclose(h); // Oops. some_struct.callback is crash if called
在
core
转储/ GDB中,您应该知道.callback
的值。假设它是p == 0x7f...1234
.
你也知道
addr
在some_func
的地址libsomelib.so
(来自nm libsomelib.so | grep some_func
)。
加载地址为
p - addr
,可以使用GDBadd-symbol-file load_address
.
但是请注意,
load_address
GDB 想要的是not p - addr
;这是p - addr + &.text-in-libsomelib.so
。您可以使用.text
找到
readelf -WS libsomelib.so | grep '\.text'
的地址