C gdb lldb что это
Перейти к содержимому

C gdb lldb что это

  • автор:

GDB vs LLDB

Both gdb and lldb are excellent debuggers. GDB is part of the GNU framework, and was created to work alongside of g++ , which is the GNU C++ compiler. LLDB is part of the LLVM framework, and was created to work alongside of clang++ , which is the LLVM C++ compiler.

Ideally, you would use the debugger of the same framework that the compiler is part of. However, a bug with LLVM prevents it from working inside a Ubuntu VirtualBox image (see here for the bug tracker about this issue). Thus, we are going to use gdb instead of lldb, even though we will continue to use the clang++ compiler.

Both debuggers can debug code compiled by either compiler. The only real differences, as far as this class is concerned, have to do with some of the commands. There are other differences between the debuggers, but those differences are not commands that we will see in this course. The full list of commands can be found on the GDB command summary page and the LLDB command summary page.

The majority of the commands are the same; this document only highlights the commands that are different between the two debuggers. The categories listed below match those on the two specific debugger pages (GDB command summary and LLDB command summary).

What is the Difference Between LLDB and GDB

The main difference between LLDB and GDB is that in LLDB, the programmer can debug programs written in C, Objective C and C++ while, in GDB, the programmer can debug programs written in Ada, C, C++, Objective C, Pascal, FORTRAN and Go.

Generally, a debugger is a computer program that helps to test and debug other programs. LLDB and GDB are two debuggers.

Key Areas Covered

1. What is LLDB
-Definition, Functionality
2. What is GDB
-Definition, Functionality
3. Difference Between LLDB and GDB
-Comparison of key differences

Key Terms

Debugger, LLDB, GDB

Difference Between LLDB and GDB - Comparison Summary

What is LLDB

LLDB is a debugger of the LLVM project. It is a free and open-source software under the University of Illinois / NCSA Open Source License. Moreover, it is built as a set of reusable components. LLDB helps to debug various programs. Programmers can debug programs written in C, Objective C and C++. Furthermore, LLDB is the default debugger of Xcode 5 and newer versions. Additionally, IDEs such as Visual Studio Code and Eclipse supports LLDB.

What is GDB

GDB is also called the GNU Debugger. It is a portable debugger and it executes on various UNIX similar operating systems. It supports various programming languages such as C, C++ Objective C, Pascal, Go and FORTRAN. GDB debugger is capable of tracing and changing the execution of a computer program. The programmer can modify the values of the program’s internal variables. Furthermore, he can call the required functions. Additionally, version 7.0 provides support for reversible debugging. In other words, it allows a debugging session to step back or to rewind a crashed program to figure out what is the issue.

Difference Between LLDB and GDB

Overall, GDB helps to start a program and stop executing a program. It also allows examining what happened to the program and programmers can change the program. Programmer can correct one bug and then move on to the other etc.

Difference Between LLDB and GDB

Definition

LLDB is the debugger component of the LLVM project. But, GDB is a portable debugger that runs on many UNIX like systems and works for many programming languages. Thus, this is the main difference between LLDB and GDB.

Developer

LLVM Developer Group developed LLDB while GNU Project is the developer of GDB.

Written in

Another difference between LLDB and GDB is that LLDB is written in C++ whereas GDB is written in C.

Supporting languages

In LLDB, the programmer can debug programs written in C, Objective C and C++ whereas, in GDB, the programmer can debug programs written in Ada, C, C++, Objective C, Pascal, FORTRAN and Go.

Operating Systems

Moreover, LLDB works on operating systems such as macOS i386 and x86-64, Linux, FreeBSD, Windows. On the other hand, GDB works on operating systems such as UNIX and Windows.

Conclusion

In brief, LLDB and GDB are two debuggers. The main difference between LLDB and GDB is that in LLDB, the programmer can debug programs written in C, Objective C and C++ while, in GDB, the programmer can debug programs written in Ada, C, C++, Objective C, Pascal, FORTRAN and Go.

References:

1.“LLDB (Debugger).” Wikipedia, Wikimedia Foundation, 9 June 2019, Available here.
2.“GNU Debugger.” Wikipedia, Wikimedia Foundation, 28 July 2019, Available here.
3.GDB: The GNU Project Debugger, Available here.

Debug C++ in Visual Studio Code

After you have set up the basics of your debugging environment as specified in the configuration tutorials for each target compiler/platform, you can learn more details about debugging C/C++ in this section.

Visual Studio Code supports the following debuggers for C/C++ depending on the operating system you are using:

  • Linux: GDB
  • macOS: LLDB or GDB
  • Windows: the Visual Studio Windows Debugger or GDB (using Cygwin or MinGW)

Windows debugging with GDB

You can debug Windows applications created using Cygwin or MinGW by using VS Code. To use Cygwin or MinGW debugging features, the debugger path must be set manually in the launch configuration ( launch.json ). To debug your Cygwin or MinGW application, add the miDebuggerPath property and set its value to the location of the corresponding gdb.exe for your Cygwin or MinGW environment.

Cygwin/MinGW debugging on Windows supports both attach and launch debugging scenarios.

If you are debugging with GDB on Windows, see Windows Debugging with MinGW64.

Conditional breakpoints

Conditional breakpoints enable you to break execution on a particular line of code only when the value of the condition is true. To set a conditional breakpoint, right-click on an existing breakpoint and select Edit Breakpoint. This opens a small peek window where you can enter the condition that must evaluate to true in order for the breakpoint to be hit during debugging.

A conditional break

In the editor, conditional breakpoints are indicated by a breakpoint symbol that has a black equals sign inside of it. You can place the cursor over a conditional breakpoint to show its condition.

Function breakpoints

Function breakpoints enable you to break execution at the beginning of a function instead of on a particular line of code. To set a function breakpoint, on the Run view right-click inside the Breakpoints section, then choose Add Function Breakpoint and enter the name of the function on which you want to break execution.

Expression evaluation

VS Code supports expression evaluation in several contexts:

  • You can type an expression into the Watch section of the Run view and it will be evaluated each time a breakpoint is hit.
  • You can type an expression into the Debug Console and it will be evaluated only once.
  • You can evaluate any expression that appears in your code while you’re stopped at a breakpoint.

Expressions in the Watch section take effect in the application being debugged; an expression that modifies the value of a variable will modify that variable for the duration of the program.

Multi-threaded debugging

The C/C++ extension for VS Code has the ability to debug multi-threaded programs. All threads and their call stacks appear in the Call Stack section:

Multi-threaded process

Memory dump debugging

The C/C++ extension for VS Code also has the ability to debug memory dumps. To debug a memory dump, open your launch.json file and add the coreDumpPath (for GDB or LLDB) or dumpPath (for the Visual Studio Windows Debugger) property to the C++ Launch configuration, set its value to be a string containing the path to the memory dump. This will even work for x86 programs being debugged on an x64 machine.

Additional symbols

If there are additional directories where the debugger can find symbol files (for example, .pdb files for the Visual Studio Windows Debugger), they can be specified by adding the additionalSOLibSearchPath (for GDB or LLDB) or symbolSearchPath (for the Visual Studio Windows Debugger).

Locate source files

The source file location can be changed if the source files are not located in the compilation location. This is done by simple replacement pairs added in the sourceFileMap section. The first match in this list will be used.

GDB, LLDB, and LLDB-MI Commands (GDB/LLDB)

For the C++ (GDB/LLDB) debugging environment, you can execute GDB, LLDB and LLDB-MI commands directly through the debug console with the -exec command, but be careful, executing commands directly in the debug console is untested and might crash VS Code in some cases.

Other debugging features

  • Unconditional breakpoints
  • Watch window
  • Call stack
  • Stepping

For more information on debugging with VS Code, see this introduction to debugging in VS Code.

For additional ways to configure the launch.json file so that you can debug your C/C++ app, see Configure C/C++ debugging.

Natvis framework

You create custom views of C++ object in the debugger with the Natvis framework. You can read the Custom views for native objects topic for details on using Natvis with the C/C++ extension.

Debug remotely

For information about attaching to a remote process, such as debugging a process in a Docker container, see Pipe transport.

Debug the debugger

If you are experiencing a debugging problem with the extension that we can’t diagnose based on information in your issue report, we might ask you to enable logging and send us your logs. See Enable logging for the debug adapter to learn how to get C/C++ extension logs.

Known limitations

Symbols and code navigation

  • Because the extension doesn’t parse function bodies, Peek Definition and Go to Definition don’t work for symbols defined inside the body of a function.

Debugging

  • GDB on Cygwin and MinGW cannot break a running process. To set a breakpoint when the application is running (not stopped under the debugger), or to pause the application being debugged, press Ctrl-C in the application’s terminal.
  • GDB on Cygwin cannot open core dumps.
    You may see an error saying: ptrace: Operation not permitted . This is due to GDB needing elevated permissions in order to attach to a process. This can be solved using the solutions below:

When using attach to process, you need to provide your password before the debugging session can begin.

To disable this error temporarily, use the following command:

echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope

To remove the error permanently, add a file called 10-ptrace.conf to /etc/sysctl.d/ and add the following kernel.yama.ptrace_scope = 0 .

  • LLDB:
    • When debugging with LLDB, if the Terminal window is closed while in break mode, debugging does not stop. Debugging can be stopped by pressing the Stop button.
    • When debugging is stopped the Terminal window is not closed.
    • Additional manual install steps are required to use GDB on macOS. See Manual Installation of GDB for OS X in the README.
    • When attaching to a process with GDB, the application being debugged cannot be interrupted. GDB will only bind breakpoints set while the application is not running (either before attaching to the application, or while the application is in a stopped state). This is due to a bug in GDB.
    • Core dumps cannot be loaded when debugging with GDB because GDB does not support the core dump format used in macOS.
    • When attached to a process with GDB, break-all will end the process.

    Next steps

    Read on to find out about:

    If you have any other questions or run into any issues, please file an issue on GitHub.

    Debugging C with GDB and Valgrind

    Debugging C can be a chore, but being able to pinpoint your memory leaks with Valgrind and monitoring the flow of your program with GDB (or LLDB) can speed up the development of your code significantly. It’s a significant improvement over sticking a bunch of printf statements in your code and taking them out before production (which should by no means be your sole tool for debugging).

    Setup

    Installing gdb is pretty easy on both OS X and Linux. Use your favorite package manager to install gcc and gdb. You can also install the LLVM compiler collection which uses lldb as its debugging tool rather than gdb.

    Installing Valgrind is similar — fire up your favorite package manager, build from source, or download a release directly from the webpage. On MacOS, there are some caveats if you’re trying to install Valgrind on MacOS > 10.12.

    Usage

    GDB/LLDB

    GDB and LLDB allow a user to scrutizine the execution of their programs line by line. You can look at the state of your program, inspecting variables, seeing what is executing, and even evaluating arbitrary statements based on the state of your program. We will examine how to use these programs.

    The basics

    Both GDB/LLDB provide some basic debugging functions like:

    • step next
    • step over
    • continue execution
    • step into
    • break

    GDB allows you to inspect your code by viewing its state as it executes on a per line basis. You can step through your program line by line. More commonly, if you suspect that your problem is in a particular segment of code, you can create a breakpoint at a function or a line number. You can do some powerful things while you step through your program like inspect what variables are in your program, and execute arbitrary statements based on the state of your program.

    GDB/LLDB gives you access to certain key commands that will help you debug your program. next will execute the current line, and the pause at the next line. This will not go into any functions, it will block gdb until the instructions on the current line have been executed. step (aka step into) will actually step into the function on the current line. If you have a function call on the current line, then GDB will “step into” that function, allowing you to continue debugging line by line inside the function. finish is like stepping out — it will continue execution until the function of the current line finishes executing/until it returns.

    You can find a reference for these commands (in GDB) here. Here is a cheat sheet from LLVM with LLDB commands and their gdb equivalents.

    Usage

    In order to run gdb, you need to make sure that your binary has debug symbols so that GDB knows the relationship between what is being executed and your code. You compiling with optimization flags ( -OX ) can cause issues because an optimization may not necessarily stay true to your code. For example, a compiler will not keep unused variables because they waste stack space. To stay safe, compile debug builds without any optimizations. You can use an optimization flag with the debug symbols. The flag is -g , so when compiling with gcc, add the -g flag to your list of flags. We will explore an example with an example program I created.

    Example

    Setup

    You can download my example source code here

    You can compile the code with this command

    Try running the code. It seems like it should work. It’s simple, it just allocates a string and initializes it to «hello» .

    You can run the code with the following command:

    The output I got was:

    So what happened? Let’s step through this program with GDB. Using LLDB should be extremely similar.

    Debug

    In order to start running gdb, we have to give it a program to run. GDB takes a binary followed by its arguments to initialize the debug runtime.

    If we had arguments, we’d use something like gdb —args gve arg1 arg2 .

    Now GDB is initialized with our program, gve (GDB Valgrind Example)

    Here’s what you’ll see at first (or something like this)

    We want to set a breakpoint at the main function. Otherwise, GDB will just run without giving us anything useful to look at.

    Let’s run the program, (just type in run )

    Now GDB is frozen at the beginning of the main function. Let’s step through the main function and see what’s happening to the str variable before and after we call init_str .

    Right before we call init_str , let’s check the value of str by calling p str

    We can see that str is NULL , as it was assigned. Let’s step and see what happens after we call init_str . Theoretically, str should be changed to “hello” after init_str is called.

    We can see that str is still NULL . Now we know the function is not working as intended. We could do two things: we could rerun the program and step until we reach the init_str function call, or we could just set a breakpoint directly at the function. Let’s set a breakpoint, since it’ll be faster.

    We’ve already gone past the function call, so we will have to restart the program. Let’s set a breakpoint at init_str then restart the program.

    Our breakpoint set earlier is still there (at main ). We don’t want to step all the way to the function, so let’s continue until we hit the next breakpoint.

    Now we’ve reached the start of the init_str function. GDB tells us which file and line the breakpoint is one. It also tells us the value of the argument: str = 0x0 . So we know str=NULL when init_str is starting. Let’s step through the function, inspecting the variables as we go through, so we can see what’s going on.

    It looks like str gets allocated correctly as evidence by $4 . It is assigned correctly with strcpy , but when we return, str becomes NULL again.

    This means that we’re not actually changing str outside of the scope of init_str . This is because we need some pointer indirection — to affect a variable outside of its enclosing scope, we need a pointer to that variable. It’s essentially the same here: we need a pointer to our char* .

    We can easily rectify the problem by passing a reference to our string rather than passing in the string directly. This is called indirection. Let’s fix the program:

    Let’s go ahead and check that the program is working as intended. Recompile the file and load it with GDB. Let’s set a breakpoint right before and right after the function call so we can see if str was allocated/set properly.

    We can see that the string now reads “hello”. The program has been corrected.

    Valgrind

    Even if a program is working correctly or appears to be working correctly, memory errors could be present that you’ll never see, or will pop up seemingly randomly in a manner that makes it difficult to diagnose with GDB.

    Valgrind is a tool that inspects your binary to see if there are any memory errors or leaks. It’s a very powerful tool that you should use to inspect your programs to ensure program correctness.

    The basics

    Valgrind contains a number of tools that you can use to help you diagnose/inspect your program. You can initialize a certain tool by passing an argument flag to Valgrind. We’re going to use memcheck, which is described here. There are other tools available that are very helpful for increasing the performance of your C/C++ programs, but this particular post will not cover them. The memcheck tool will run your program, display output, and display errors as they arise while the program is executing.

    The example usage for our program would be valgrind —tool=memcheck —leak-check=full

    We have a memory leak! We’ve lost 5 bytes from where we called malloc in the init_str method. This means that we forgot to free the string that we allocated. Let’s fix this and then run Valgrind again.

    Here is the corrected program:

    Here is the Valgrind output:

    There are some errors, but we fixed the memory leak! I will address these errors later or in another blog post.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *