Debugging assembly - debugging

How do I debug assembly code? I'm on Linux and have gdb handy. I know I can watch registers. What are some methods for debugging assembly code?

You can of course use breakpoints just as with C or any other compiled language, too. This article describes the process of debugging an assembly program a bit.

Using the "disassemble" gdb command you can see the assembly code that is about to be executed. This, in conjunction with watching registers, can give you insight into what the CPU is really doing.

Of course you can use nm command with a parameter of executable elf file, it will shows you the available labels with address. From this you can set a breakpoint on a specific address, then execute a single instruction by using "si" debug command.

Related

Assembly code breakpoint does not work as expected

I am developing a STM32F2 device using GCC 4.7.4 and a Lauterbach Combiprobe JTAG debugger. In my code, I have the following statement to always break at a certain spot for testing purposes:
asm volatile ("BKPT #0");
This is the only breakpoint. When I run the program, I can see that my program reaches the breakpoint, but I cannot step beyond this breakpoint using my JTAG debugger. Instead, I have to move the PC counter past this instruction to get the program to execute.
This was working in the past, but I am at a loss to figure out why the behavior is different now. Any clues or hints would be appreciated.
There are so many broken JTAG debuggers. Probably you installed an update for the JTAG adapter?
When you have GDB as Debugger you might check if you can add a macro set PC=PC+4 to a button or key. But if this is possible depends on your IDE.
There is no general rule what happens with the program counter if you have a breakpoint instruction in you application code. Some CPUs stop at the address containing the breakpoint instruction, others stop after the breakpoint instruction.
Since you use the tag "lauterbach" I assume you are using a TRACE32 debugger from Lauterbach.
If you think the debuggers behavior was different in the past, I think you should contact the Lauterbach support.
For now you can workaround the issue with the following TRACE32 command
Break.Set T:0x1000 /Program /CMD "Register.Set PP r(PP)+2"
(where 0x1000 stands for the address, where your BKPT instruction is located.)

Is there any flex ("Fast LEXical analyzer") debugger out there?

I'm studying "Compilers" and we work on Flex to program.
I create *.lex files (with any editor), convert them into lex.yy.c via flex, and then compile to a.exe using gcc.
Writing lex code in an editor like Notepad/Codeblocks/... is not only hard because everything is just BLACK, but also there is no debugging system.
The gcc compiler does tell about errors, but what i'm looking for is something i can go line by line with the code (in runtime) and see what's going on with the variables. Like the command F10 in Visual Studio.
Does anybody know a suitable program for this? Thanks alot
Concerning hightlighting, using gedit(The default GUI editor on Ubuntu and some other Linux variants) or even vim will provide that for you, you don't have to use plain notepad.
As for the debugging, yes there's what's called the GNU Debugger (aka GDB) which allows you to do typical debugging jobs after you've compiled your code, you can step line by line and examine certain variable values.
Before doing that, first compile your program with the gcc flag -g to add debug symbols to the complied result, then run gdb yourProgramName, this will run GDB and you'll be able, using certain commands, to do whatever debugging tasks you want.
I once wrote a little guide to help people get started with GDB, it might be useful.

.ASM file debugging tool

I am wondering which debugging tool I can use for an assembly program and how to use it.
I have written a simple bootloader in assembly. However, it is not quite working properly as I wished, even though I think the logic is correct. So, I am trying to use a debugger so that I can step through the bootloader, checking the register status and etc.
I tried GDB on Ubuntu, compiling my .asm to .elf and .o (Do I need to do it? If yes, what is the next step?) Also, I read that there is an internal debugger in Bochs simulator, but I can't quite find any document how to use it. I also have Visual Studio 2010, windbg, but I don't know how to use it for .asm file debugging.
If you have done this before, it would be an easy answer. Any help would be really appreciated.
Sincerely
If you want to debug bootloader code, you obviously need to run it in the same environment that the code itself is going to run in. As I'm sure you already know, bootloader code is executed in real mode once the BIOS finishes doing the POST. The bootloader is then loaded into memory at 7c00h and a jump to that address is executed.
Obviously, this kind of environment cannot be reliably emulated once you've got your computer running and a "real" operating system already loaded, since by that time your CPU is in protected mode (or long mode, if it's AMD64). Your only option at this point is to use QEMU or Bochs in order to emulate a real PC inside your operating system. I've used Bochs to debug some bootloader code I've written in the past and it worked quite well. Check the manual pages for more detailed instructions.

Debugging without a debugger

I have some crashes in some C code, built without debugging symbols, and I have only a backtrace with the absolute addresses of the call stack. This is on windows (64 bits). I am more of a linux guy, so I am a bit lost at how to look into debugging this - on Linux, I would run the code under valgrind, but AFAIK, no such tool exists for windows 64 bits.
What are my options ? I can modify the C code at will, but I cannot build it with the debug symbols. The reason why I cannot build with debugging symbols is that my binary is not built with MS tools (it is built with mingw-w64).
You need to generate a map file. A map file lists out the addresses of various public symbols (functions, globals etc) in your executable/binary. Usually it can be generated by passign on a special switch to the linker.
MSDN reference for /MAP
You should probably be using the ming version of gdb, which can understand the symbols embedded in the binary.

How does a debugger work?

I keep wondering how does a debugger work? Particulary the one that can be 'attached' to already running executable. I understand that compiler translates code to machine language, but then how does debugger 'know' what it is being attached to?
The details of how a debugger works will depend on what you are debugging, and what the OS is. For native debugging on Windows you can find some details on MSDN: Win32 Debugging API.
The user tells the debugger which process to attach to, either by name or by process ID. If it is a name then the debugger will look up the process ID, and initiate the debug session via a system call; under Windows this would be DebugActiveProcess.
Once attached, the debugger will enter an event loop much like for any UI, but instead of events coming from the windowing system, the OS will generate events based on what happens in the process being debugged – for example an exception occurring. See WaitForDebugEvent.
The debugger is able to read and write the target process' virtual memory, and even adjust its register values through APIs provided by the OS. See the list of debugging functions for Windows.
The debugger is able to use information from symbol files to translate from addresses to variable names and locations in the source code. The symbol file information is a separate set of APIs and isn't a core part of the OS as such. On Windows this is through the Debug Interface Access SDK.
If you are debugging a managed environment (.NET, Java, etc.) the process will typically look similar, but the details are different, as the virtual machine environment provides the debug API rather than the underlying OS.
As I understand it:
For software breakpoints on x86, the debugger replaces the first byte of the instruction with CC (int3). This is done with WriteProcessMemory on Windows. When the CPU gets to that instruction, and executes the int3, this causes the CPU to generate a debug exception. The OS receives this interrupt, realizes the process is being debugged, and notifies the debugger process that the breakpoint was hit.
After the breakpoint is hit and the process is stopped, the debugger looks in its list of breakpoints, and replaces the CC with the byte that was there originally. The debugger sets TF, the Trap Flag in EFLAGS (by modifying the CONTEXT), and continues the process. The Trap Flag causes the CPU to automatically generate a single-step exception (INT 1) on the next instruction.
When the process being debugged stops the next time, the debugger again replaces the first byte of the breakpoint instruction with CC, and the process continues.
I'm not sure if this is exactly how it's implemented by all debuggers, but I've written a Win32 program that manages to debug itself using this mechanism. Completely useless, but educational.
In Linux, debugging a process begins with the ptrace(2) system call. This article has a great tutorial on how to use ptrace to implement some simple debugging constructs.
If you're on a Windows OS, a great resource for this would be "Debugging Applications for Microsoft .NET and Microsoft Windows" by John Robbins:
http://www.amazon.com/dp/0735615365
(or even the older edition: "Debugging Applications")
The book has has a chapter on how a debugger works that includes code for a couple of simple (but working) debuggers.
Since I'm not familiar with details of Unix/Linux debugging, this stuff may not apply at all to other OS's. But I'd guess that as an introduction to a very complex subject the concepts - if not the details and APIs - should 'port' to most any OS.
I think there are two main questions to answer here:
1. How the debugger knows that an exception occurred?
When an exception occurs in a process that’s being debugged, the debugger gets notified by the OS before any user exception handlers defined in the target process are given a chance to respond to the exception. If the debugger chooses not to handle this (first-chance) exception notification, the exception dispatching sequence proceeds further and the target thread is then given a chance to handle the exception if it wants to do so. If the SEH exception is not handled by the target process, the debugger is then sent another debug event, called a second-chance notification, to inform it that an unhandled exception occurred in the target process. Source
2. How the debugger knows how to stop on a breakpoint?
The simplified answer is: When you put a break-point into the program, the debugger replaces your code at that point with a int3 instruction which is a software interrupt. As an effect the program is suspended and the debugger is called.
Another valuable source to understand debugging is Intel CPU manual (Intel® 64 and IA-32 Architectures
Software Developer’s Manual). In the volume 3A, chapter 16, it introduced the hardware support of debugging, such as special exceptions and hardware debugging registers. Following is from that chapter:
T (trap) flag, TSS — Generates a debug exception (#DB) when an attempt is
made to switch to a task with the T flag set in its TSS.
I am not sure whether Window or Linux use this flag or not, but it is very interesting to read that chapter.
Hope this helps someone.
My understanding is that when you compile an application or DLL file, whatever it compiles to contains symbols representing the functions and the variables.
When you have a debug build, these symbols are far more detailed than when it's a release build, thus allowing the debugger to give you more information. When you attach the debugger to a process, it looks at which functions are currently being accessed and resolves all the available debugging symbols from here (since it knows what the internals of the compiled file looks like, it can acertain what might be in the memory, with contents of ints, floats, strings, etc.). Like the first poster said, this information and how these symbols work greatly depends on the environment and the language.

Resources