简体   繁体   English

无法使用 GDB 进入共享库中的函数

[英]Unable to step into a function in a shared library with GDB

I am trying to debug an application that is built from a number of shared libraries using GDB.我正在尝试使用 GDB 调试从多个共享库构建的应用程序。

Start of gdb: gdb 的开始:

prompt$ gdb
GNU gdb (GDB) Red Hat Enterprise Linux (7.2-50.el6)
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.

Tell GDB the program to debug:告诉 GDB 要调试的程序:

(gdb) file /home/me/build-path/my-program
Reading symbols from /home/me/build-path/my-program...done.

Set a breakpoint within the application:在应用程序中设置断点:

(gdb) my-program-src.cpp:57
breakpoint 1 at 0x819df9b: file src/my-program-src.cpp, line 57

Run the program:运行程序:

(gdb) run 
 Starting program: /home/me/build-path/my-program

The program stops at the breakpoint, as expected:程序在断点处停止,正如预期的那样:

 Breakpoint 1 MyClass:func(this-0xffffc1c0) at src/my-program-src.cpp:235

Line 235 of my-program-src.cpp is a constructor call for class Derived which is in MySharedLib1.so . 235行my-program-src.cpp是一个构造函数调用了class Derived是在MySharedLib1.so

'class Derived' is derived from 'class Base' which is in MySharedLib2.so “class Derived”派生自MySharedLib2.so “class Base”

If I now step, the program exits inside `MySharedLib2.so' with a SIG SEGV (which is what I am trying to debug), ie:如果我现在单步执行,程序会在带有 SIG SEGV(这是我要调试的内容)的“MySharedLib2.so”中退出,即:

Program received signal SIGSEGV, Segmentation fault.
0x0024c2fa in osal::MsgQMsg::id(unsigned int) () from /home/me/build-path/lib/libMySharedLib2.so

GDB is not stepping into either of the shared libraries. GDB 没有进入任何一个共享库。

bt gives the name of the function where the problem occurred, but list shows code in my-program-src.cpp bt给出了发生问题的函数的名称,但list显示了my-program-src.cpp代码

All code is compiled with the following options:所有代码都使用以下选项编译:

gcc -MD -D__LINUX__  -g -Wall -Wextra -Iinc -m32 -fpic -I../../public_inc /home/me/src/file.c -o /home/me/build-path/obj/file.o

The shared libraries are linked with the following options:共享库与以下选项链接:

gcc -o /home/me/build-path/lib/libMySharedLib1.so -shared /home/me/build-path/obj/file.o -L/home/me/build-path/lib/ -m32

If I change the Makefiles so that archives libraries are build (ie .a ) I can step into functions as expected.如果我更改 Makefiles 以便构建档案库(即.a ),我可以按预期进入函数。

Further information:更多信息:

If I manually try to add the symbols from the shared library I get the following:如果我手动尝试从共享库中添加符号,我会得到以下信息:

(gdb) add-symbol-file  /home/me/build-path/lib/libMySharedLib2.so
The address where /home/me/build-path/lib/libMySharedLib2.so has been loaded is missing

(Note: i get the same response from add-symbol-file once the breakpoint has been hit) (注意:一旦断点被​​击中,我会从add-symbol-file得到相同的响应)

If I can set a breakpoint in a function within the shared library, GDB breaks as expected but if I type list GDB shows the calling line in the main application code (ie the calling function that is not in a shared library).如果我可以在共享库中的函数中设置断点,GDB 会按预期中断,但如果我键入list GDB 会显示主应用程序代码中的调用行(即不在共享库中的调用函数)。 GDB does not complain about source files not being found. GDB 不会抱怨找不到源文件。

Why can't I step into my shared libraries?为什么我不能进入我的共享库?

Why can't I step through code in shared libraries?为什么我不能单步执行共享库中的代码?

If the shared library has no debug symbols/info, gdb will by default step over it rather than into it.如果共享库没有调试符号/信息,默认情况下 gdb 将跳过它而不是进入它。 You can use stepi (abbrev si ) to instead step by single instructions.您可以使用stepi (缩写si )来代替单个指令。 I find the following commands in by .gdbinit file useful:我发现 .gdbinit 文件中的以下命令很有用:

define sx
  si
  x /1i $pc
end
document sx
    Step one instruction and print next instruction
end
define nx
  ni
  x /1i $pc
end
document nx
    Step one instruction running through calls and print next instruction
end

which defines the commands sx / nx to step by single instructions, and then disassemble the next instruction to be run.它定义了命令sx / nx以单条指令步进,然后反汇编要运行的下一条指令。 Quite useful when trying to debug through machine code with no debug info.在尝试通过没有调试信息的机器代码进行调试时非常有用。

It may be a typo, but you used libMySharedLib2.so with a 2 not a 1 when you tried to load the symbols.这可能是一个错字,但是当您尝试加载符号时,您使用了libMySharedLib2.so2而不是1

In any case, you should use g++ to compile and link c++ code.在任何情况下,您都应该使用g++来编译和链接 c++ 代码。 Furthermore, the main program doesn't have to be pic, although it probably doesn't hurt.此外,主程序不必是图片,尽管它可能不会受到伤害。

It works for me as follows:它适用于我如下:

$ cat >lib.h
class Base
{
        int _x;
    public:
        Base(int);
};

class Derived : public Base
{
    public:
        Derived(int x);
};
$ cat >lib.cpp
#include "lib.h"

Base::Base(int x)
{
    _x = *reinterpret_cast<int*>(x);
}

Derived::Derived(int x) : Base(x)
{
}
$ cat >main.cpp
#include "lib.h"

int main(int, char**)
{
    Derived d(0);
    return 0;
}
$ g++ -shared -fpic -m32 -g -Wall -o libMySharedLib1.so lib.cpp
$ g++ -m32 -g -Wall -L. -l MySharedLib1 main.cpp
$ LD_LIBRARY_PATH=$PWD gdb ./a.out
GNU gdb (GDB) 7.3.50.20111117-cvs-debian
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from a.out...done.
(gdb) r
Starting program: a.out     

Program received signal SIGSEGV, Segmentation fault.
0xf7fdb552 in Base::Base (this=0xffffd83c, x=0) at lib.cpp:5
5           _x = *reinterpret_cast<int*>(x);
(gdb) bt
#0  0xf7fdb552 in Base::Base (this=0xffffd83c, x=0) at lib.cpp:5
#1  0xf7fdb5ba in Derived::Derived (this=0xffffd83c, x=0) at lib.cpp:8
#2  0x08048591 in main () at main.cpp:5
(gdb) br main
Breakpoint 1 at 0x804857d: file main.cpp, line 5.
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: a.out     

Breakpoint 1, main () at main.cpp:5
5           Derived d(0);
(gdb) s
Derived::Derived (this=0xffffd83c, x=0) at lib.cpp:8
8       Derived::Derived(int x) : Base(x)
(gdb) s
Base::Base (this=0xffffd83c, x=0) at lib.cpp:5
5           _x = *reinterpret_cast<int*>(x);

(gdb output slightly edited) (gdb 输出略有编辑)

This is a problem typically experienced by using libraries which were not compiled with debug statements.这是使用未使用调试语句编译的库时通常会遇到的问题。 In general, gdb will step over those functions and the backtrace will provide a location only in loaded memory of the library call.通常,gdb 将跳过这些函数,并且回溯将仅在库调用的加载内存中提供一个位置。 This is because without those symbols, gdb has nothing to map.这是因为没有这些符号,gdb 就没有什么可映射的。

If you have the source of the library itself, recompile it with the debug flags activated.如果您有库本身的源代码,请在激活调试标志的情况下重新编译它。 Depending on what you are debugging, this can introduce timing artifacts into your analysis.根据您正在调试的内容,这可能会在您的分析中引入时序伪影。 For example, if you're debugging a segfault in some buffer that the data was streamed into, the presence of the symbols will introduce enough latency to let a buffer fill properly.例如,如果您正在调试数据流入的某个缓冲区中的段错误,则符号的存在将引入足够的延迟以使缓冲区正确填充。

If you do not have the source code, this is exceptionally challenging, but not impossible in many cases.如果您没有源代码,这将非常具有挑战性,但在许多情况下并非不可能。 If the library wasn't stripped , the backtrace does provide enough information to understand which functions were in execution at the event of the error.如果库没有被剥离,回溯会提供足够的信息来了解在发生错误时哪些函数正在执行。 With that, you'll need to reverse-engineer the execution to the point where you can review whatever source files you have available.有了这个,您需要对执行进行逆向工程,以便您可以查看任何可用的源文件。 Depending on your familiarity with the ISA, you could tease out some of these details yourself by looking at the assembly instructions.根据您对 ISA 的熟悉程度,您可以通过查看组装说明自行梳理其中的一些细节。

The worst-case scenario is if the library was completely stripped .最坏的情况是库被完全剥离 This is a process of pairing down all of the compiled code such that all human-readable (really text string) references within it are removed.这是一个配对所有编译代码的过程,以便删除其中的所有人类可读(真正的文本字符串)引用。 The compiler even in the absence of debug statements will still leave labels with the names of the functions, but strip will replace those with a unique integer (it leaves other things, but I think you can understand what I'm getting at here).即使在没有调试语句的情况下,编译器仍然会留下带有函数名称的标签,但是strip会用唯一的整数替换那些标签(它会留下其他东西,但我想你可以理解我在这里得到的东西)。 In this case, gdb cannot even resolve a function name in a backtrace.在这种情况下,gdb 甚至无法在回溯中解析函数名称。 This is where your understanding of the ISA needs to shine, and when you'll first have to go through a rigorous reverse-engineering project before even tackling the cause of the error itself.这就是您对 ISA 的理解需要发挥作用的地方,并且在解决错误本身的原因之前,您首先必须通过严格的逆向工程项目。

In the major trouble-class (that is, you don't have the source code), you need to ask yourself an important question: Am I responsible for fixing what is not my code?在重大问题类(即您没有源代码)中,您需要问自己一个重要问题:我是否负责修复不是我的代码的内容? In most cases, focus on ensuring the error is reproducible and file a bug-report;在大多数情况下,专注于确保错误是可重现的并提交错误报告; let the maintainers of that library figure it out.让那个库的维护者弄清楚。 If you're still responsible for fixing the overall error, focus on what you can affect and black-box what you cannot;如果您仍然负责修复整体错误,请专注于您可以影响的部分,并黑箱化您不能影响的部分; see if you need to constrain the input to those library calls in such a way that you can appropriately prevent or handle the error.查看是否需要以可以适当地防止或处理错误的方式限制对这些库调用的输入。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM