Using GDB without debugging symbols on x86? - debugging

How do I use GDB to debug a program which do not have debugging symbols on a 32-bit x86 processor? Inspecting the function arguments, local variables, resolving pointers would be useful to know how to do.
The intention is not really to use this for reverse engineering, as I'm sometimes just too lazy to install the debugging symbols and would be great to know how to get some basic information out of gdb.

To start out, you can do;
gdb "whatever"
break __libc_start_main
r
that will setup a breakpoint in libc's crt0 code and allow you to break before main, even if the target binary is totally stripped.
That will get you to a running state at a breakpoint before most user code. You can then single step, dissasemble, dump memory etc... to your heart's content.
This works on all platforms, the fact your asking about IA-32 / x86 does not matter.

Without debugging symbols, you can only debug at the ASM level. Ok you get a bit more information, but you're not going to get very far unless you understand a bit of ASM and the code the compiler generates. This will let you do a simple inspection of local variables etc if you know what you're doing.
If you have the source, it's going to be far easier just to recompile it.

All you can do is look at registers and the contents of the stack - you'll have to do everything by inferring what things are used for, as Draemon mentions.

Well, the absolutely most important thing is that you be able to unwind the stack. There are three ways this can be ensured:
Build debugging symbols with -g
On systems that do C++ exception unwinding via tables (probably anything ELF these days?), the -funwind-tables flag will tell it to generate such tables regardless of language, and GDB can use these tables (at least, with x86 linux it can).
Or, failing those, at least make sure that -fomit-frame-pointer isn't enabled

Related

GDB or Radare2?

Should I use GDB or Radare2 for reversing an executable(I am a beginner)?
I try to programming in C and I got a SegFault. I want to Reverse Engineer it to get experience in Assembly and see where I get the SegFault.
For debugging an executable you built from source yourself, GDB is intended as a debugger. You can use layout reg to get a disassembly + registers view which can help understanding segfaults, if looking at C variables didn't help.
Debug info from compiling with gcc -g means you don't need to reverse-engineer anything, just use a normal debugger. But to get experience in asm, using a debugger both ways (source view and asm view) can help you understand how the compiler used certain asm instructions to implement each C statement. So you definitely want a debugger that can take advantage of debug info. There are some GUI GDB front-ends, like https://www.gdbgui.com that can be easier to use than command-line GDB.
But see also How to remove "noise" from GCC/clang assembly output? for more about seeing how C compiles to asm.
I haven't used radare2. I assume it has features that are good for intentionally-obfuscated executables without source, which is the opposite of what you have from compiling your own C programs with a normal compiler.
I would recommend Radare2 because it's clearer than GDB and easier for beginners ;)

Investigating Segmentation Faults and Debugging Tools

After compiling a C++ program with make and gcc I experienced a segmentation fault while running. The program just exited without any error message.
Even though I didn't compile the program in debug mode, by running it with gdb I actually got an error message to see where the segfault happened.
What I would like to know is:
Why did gdb display the line causing the error, but the regular bash did not?
How can the gdb display the line when the program was not compiled in debug mode?
In the past I always re-compiled in debug mode (to attatch the symbolic table to the binaries) and investigted the backtrace of the core dump with ddd. Is this the proper way to fix segmentation faults, or what is the common way to do it?
Why did gdb display the line causing the error, but the regular bash did not?
Because gdb is built to do that. Trapping the segfault and reporting about it to you is part of its job, to help you debug. For example, you can then obtain a backtrace, examine the various stack frames, etc. to determine the nature and perhaps the cause of the error. Bash is not built to do that, and no such behavior is provided for free.
How can the gdb display the line when the program was not compiled in debug mode?
Clearly some kind of debugging information is inserted into the binary by default, even when you do not ask for it. Enough, at least, to provide line numbers for code. If you're using GCC, then that might correspond to -g1, whereas -g is equivalent to -g2. If you're curious, you could compile with -g0 to see whether that eliminates the line number information.
In the past I always re-compiled in debug mode (to attatch the symbolic table to the binaries) and investigted the backtrace of the core dump with ddd. Is this the proper way to fix segmentation faults, or what is the common way to do it?
There's no "proper" here beyond "whatever works".
I do find that its easier to debug programs compiled with optimization disabled, and of course debug information is most helpful -- all provided that you can reproduce the error with such a binary. I also tend to engage valgrind whenever a program I'm working on segfaults. That, too, is more informative when debug information is available, and if there is a memory problem (which a segfault almost invariably indicates) then valgrind will likely identify it even if the debug version of the program doesn't crash. As for ddd, that's just one of several UI choices, including supported tools' native ones. Use what works for you in that regard.
Oh, and in decades of programming, I've never yet had to resort to analyzing a core dump. My time may come eventually, of course, but I'm content to defer it.

Can I compile without debugging symbols, then create them from the source?

I have a program that takes a lot of memory and time to compile. I measured that without debugging symbols, compilation takes much less resources, but I would like to always have them, even for "release" builds so that I crash dumps are meaningful.
Is it possible to create debugging symbols (-ggdb3) with either gcc or clang for an executable that has not been originally compiled with them? I've been told that just recompiling the program with -ggdb3 works, but I don't know how much this is reliable.
Assuming the build chain is deterministic, which is a highly desirable goal for tool chains, and assuming you have not changed the source in any meaningful way (which practically means in any way at all), then running it again will be reliable. However, I am sure it is possible to demonstrate examples when this doesn't go as planned. So, as your intuition suggests, building the debugging symbols simultaneously should be considered a Good Thing.

Can I use -fstack-check when compiling my Ubuntu 10.04 kernel module?

It looks like my kernel module is performing some stack smashing under heavy loads. Can I use the -fstack-check compile option for kernel modules? It appears as if that compile option causes the compiler to emit additional code, but not link to a library or runtime. Is that correct?
I have a very simplified kernel that does not do much. I can load that simple kernel with and without slub debugging enabled, and it will also load with and without -fstack-check at compile. When I start testing my module, it starts crashing when I use the -fstack-check compile option, whereas it seems to not trip errors with just slub debugging.
A different question (How does the gcc option -fstack-check exactly work?) provided some information but I haven't been able to find examples of people using the -fstack-check option in kernel module compilations.
The stack space inside the Linux kernel is severely limited. Go over your code with a fine comb to check there are no paths using too much in local variables, no alloca() allowed at all. Other than that, the kernel environment is harsh. Check your logic carefully. Add tests for possibly out of range data, trace data to wherever it comes from and make sure it is always as you believe. Data from userland is always a reason for extra paranoia.

How does a breakpoint in debugger work?

Breakpoints are one of the coolest feature supported by most popular Debuggers like GDB. But how a breakpoint works ? What code modifications does the compiler do to achieve the breakpoint? Are there any special hardware features used to support breakpoints?
Compiler does not need to "modify" the binary in any way to support the breakpoints. However it is important, that:
Compiler includes enough information in the executable (that is not in the code itself but in special sections in same file), so that debugger can relate source that user wants to debug with machine code. One typical thing debugger needs to know to be able to set breakpoints (unless you specify addresses directly), is where (at which address) program functions and lines of source code start (within machine code).
Code is not optimized by compiler in any way, that makes it impossible to relate source and machine code. Typically you will want debug code that was not optimized or code where only carefully selected optimizations were performed.
The rest of work is then performed by debugger itself.
Software breakpoints don't necessarily need special hardware features. Debugger here relies on modifying original binary (it's copy that is loaded to memory). When you set a breakpoint, debugger will place special instruction at the location of breakpoint. This special instruction needs to somehow let debugger detect when it (this special instruction) is executing. This can be some instruction that causes some kind of interrupt/exception, that debugger can hook onto, or some instruction that handles the control to debug unit. If this runs under some OS, that OS needs to support modifying running program (with something like ptrace poke/peek). Downside of SW breakpoints is that debugger needs to be able to modify running program, which is not possible if program is running from some kind of read-only memory (quite common in embedded world).
Hardware breakpoints (which need to be supported by CPU) implement similar behavior without modifying program binary. This is CPU specific, but usually it lets you to at least define a program address at which execution should hit a breakpoint. CPU continuously compares current PC with these breakpoint addresses and once the condition is matched, it breaks the execution. Number of these breakpoints is always limited.
To put a break point first we have to add some special information in to the binary .We use the flag -g while compiling the c source files to include this info.The Software debugger actually use this info to put break points.The best example for hardware break point support is in VxWorks as I have experienced.
Basically at the break point the processor halts.So internally any step which will give an exception to processor can be used to put a software break point.While a Hardware break point works by matching the address stored in Hardware registers to cause an exception.So Hardware break point is very powerful but it is heavily architecture dependent.
A very good explanation is here
What is the difference between hardware and software breakpoints?
A good intro with Processor related information is given here
http://processors.wiki.ti.com/index.php/How_Do_Breakpoints_Work

Resources