Debugger- GDB

The basic functionality of any debugger are:

  • Start a child process and debug it
  • Attach itself to a running process
  • Set breakpoint, step into the code
  • Examine variable values
  • Trace stack
  • Etc.

Breakpoints
Breakpoints are program location where processor should halt and provide scope for debugging.
Note: There are data breakpoints as well, such as whenever NULL is referenced, hit a breakpoint.

The broad classification of breakpoints is:
Hardware Breakpoint
Special logic in integrated into device, with certain bits programmed in comparator logic. Whenever address bus carries same bits as in comparator, CPU is halted. 
These can be used for RAM as well as ROM code, as HW logic just matches address on physical address bus irrespective from which memory this address comes from.

Software Breakpoint
As we know, that compiler generates elf file which goes into execution cycle with program counter moving across specified addresses. The key challenge is to know how exactly a binary file containing program counters is used to indicate that it is time to halt CPU whenever X program counter is hit. 

There can be multiple implementations,
Purely in Software: A specific opcode is given to breakpoint, say 8 bit code. The processor works in pipeline mode, so when a breakpoint is hit, it is possible that multiple forward instructions were moving on. The CPU has to flush the pipeline and restore instructions to that of when breakpoint was to be executed.

+ Unlimited breakpoints can be placed
- May not put in ROM/Flash instructions

x86 pronounces software breakpoints as trap. Breakpoints are implemented as int 0x3  [int stands for INTERRUPT]. This generates special 8-bit opcode intended to be call exception handler. Linux sends SIGTRAP signal to such process. 
To set breakpoint at some address in program, debugger does following:

  • Remember the data stored at the target address
  • Replace the first byte at the target address with the int 3 instruction
When debugger tells OS to run a process, the process will eventually run int 3 instruction. [This process is now a child process of debugger, and any signal sent to this process will be received by debugger] At this point, debugger returns receiving SIGTRAP on its child. Debugger then,
  • Replace int 3 at target address with original instruction from breakpoint table
  • Roll-back instruction pointer back by 1 [as this instruction need to be executed again with proper instruction code, where 8-bits are restored to original]
  • Let debug happen
  • When user says go, place the 8-bit breakpoint opcode back (unless cancelled by user)

Hardware Assisted:
'very few' devices reserve a bit in opcode for Software breakpoint. All regular instructions will have that bit set to 0. Whenever a breakpoint is set, this bit is modified to 1, and emulation logic monitors this bit. Whenever found set, CPU is made to halt. 

CoreDump
Dump of main memory while process execution.
During analysis, General Purpose register state/values, stack dump, signal details which caused crash.

Core dump file can be analyzed with readelf (bin-utils).
#readelf -a corefile


Stack Overflow
Condition in which a program tries to use memory space more than what call stack has.
This is possible in case of infinite or very deep recursion, using very large stack variables,

Double Fault
Due to kernel bug, it occurs when processor faces problem in servising pending ISR, probably as ISR lies in in incorrect memory. There is double fault exception handler to get out of such situation.

Tripple Fault
Due to kernel bug, typically caused by buffer over/underflow in device driver where it writes over IDT(Interrupt Descriptor Table). When INT comes, CPU can neither enter ISR nor double fault handler.

References:


No comments:

Post a Comment