
Debugger32
-------------------------------------

This debugger will halt the system and puts the kernel into a debug state.
The entire system is halted while in this state.

With QNX's microkernel architecture it is very rare to need this tool even
when debugging device drivers. However, it can be very powerful to use when
debugging difficult interrupt handler problems, memory problems, etc.


How to use it:

- you must include the Debugger32 program in your boot image.

e.g.

#--------sample Debugger-enabled build file------------
/boot/sys/boot
$ /boot/sys/boot

/boot/sys/Proc32
$ /boot/sys/Proc32 -l 185 -P26 -o 2f8,9600 -D 

/boot/sys/Slib32
$ /boot/sys/Slib32

/boot/sys/Slib16
$ /boot/sys/Slib16

/bin/Fsys
$ /bin/Fsys 

/bin/Fsys.eide
$ /bin/Fsys.eide eide -a1f0 -i14 -vS eide -a170 -i15 -vS

/bin/mount
$ /bin/mount -p /dev/hd0 /dev/hd0t77 /

/bin/sinit
$ /bin/sinit TERM=qansi

/boot/sys/Debugger32
$ /boot/sys/Debugger32 -s 0x2f8 -b 9600 -zs

#------------------------------------------------

Note the following about the build file.
- the -D option is used on Proc32. This disables the default action of having
  the debugger halt the boot process when the system first boots.
  By default, the Debugger will bring up a debug prompt 2 times when booting:
     First time just after 'boot' has loaded the processes contained in the
     image, but the processes (Proc32, Fsys etc.) are not yet executing, *AND*
     the system is still in real mode.
     Second time, just after the switch to protected mode.

- the -zs switch to the Debugger32 tells the debugger to use the serial port
  for input. By default the debugger will use the main system console for
  input. Please note that output will appear on both the serial terminal as
  well as the main console (if active).

- Note the use of -o on Proc32 as well. This tells Proc32 to print all its
  messages that use qnx_display*() to the serial port. This is useful if you
  run in graphics mode.. by default the messages will be displayed to the
  system console, direct to the console text memory (not through Dev.ansi).
  Note that any programs you write that use the qnx_display*() services will
  also appear on the serial port if -o is specified.

Getting in to the Debugger32
-------------------------------------
There are 4 main ways to get into the Debugger:

1. by hitting CTRL-ALT-ESC from the console keyboard.

2. by issuing a software interrupt 0xF3h from a program running as root.
   See ll_debug() in /usr/include/sys/inline.h

3. by experiencing a specific fault in a user application or the kernel.

4. by hitting a watchpoint or breakpoint previously set in the Debugger.


Some useful Debugger32 tips
-------------------------------------------

Here are some tips and techniques that are useful when using the system
debugger:

/c   display ready processes (processes that are marked as READY in the
     ready queue) by entering /c
     These will be the processes that are ready to run as soon as the debug
     trap occurred.

/t
/T   display processes and proxies in use by entering /T or /t


/P is one of the most useful commands:

pid 36 -> f8:18ba0
proc(dae->0) pid 36 prio 20 state recv(3) on 0 flags 10020200
  magic 0xd:0x4998 ldt 0x218 regs S:0x18c4c,U:0x18c4c cs:ip 0x5:0x83de
  signal ignore 0xfebfbeff pending 0x0 mask 0x0 ptr 0xd:0x4b04
  code_seg 0x5 data_seg 0xd pages 30
 PROC (//370/bin/Dev32.ansi)
   sendq=0x0, clink=0 mxcount 0
cs/0005 ss/000d ds/000d es/001d fs/0030 gs/0000
edi/00004ae5 esi/0000003b ebp/0000003b ebx/000047a4 edx/00000000
ecx/00000000 eax/00000101 eip/000083de esp/000047a4 psw/00002246
trap/0 info/0 err/0 state/0

* 
---
one thing that can be deceptive is there is no explicit way to modify a
processes' register set, so suppose I wanted to change some registers in a
process I was interested in (say pid 332):

* p 332          " switched the debugger to the ldt of pid 332
* /P             " look at it's process table entry again
                 " suppose it is at cs/0005 .... eip/0000a0005
* b 5:0xa0005
* g
*                " now the debugger 'has' it's register set, you
                 " can modify them, single step, etc....

Another fancy thing that is in the debugger is 'real' watchpoints.
You have to be careful, because watchpoints are virtual addresses,
so if your program grows (alloc's memory), the watchpoint may not
point at it anymore...   
In the previous example, the breakpoint could have been set by:

* a 5:0xa0005     " get the virtual address of this location
                  " suppose it came back with: 5:a005 vaddr = 29c005 ...
* w 0 e 29c005 /1 " watchpoint 0 is execute @ 0x29c005
* g
                  " when your program executes the instruction at that
                  " location, it will invoke the debugger.

Watchpoints are more frequently used for data, and you can add a
condition. For example:

w 0 w 29c005 /1 = 6
 " stop when *(char *)0x29c005 == 6
w 0 w 29c005 /4 & 7 6
 " stop when (*(long *)0x29c005&7) == 6
w 0 w 29c005 /2 ! 0x80
 " stop when *(short *)0x29c005 != 0x80

===============================================
Quick list of Debugger32 cmds:

d{size}	[expr0	[expr1]]	display memory at expr0 for expr1 bytes.
D		expr				disassemble instructions at addr, enter disasm-mode.
i{size}	expr				read from iolocation.
o{size}	expr0 expr1			write expr1 to iolocation expr0.
e{size} expr				edit memory at location.
r	register [expr]			display/set register
a	expr					show page table entry for address.
.	expr					print segment table entry for selector.
/c							show all ready processes
/l							show process table (pid + name)
/p	expr					display memory as a proc-table entry.
/P	expr					display proc table entry for pid.
/r	expr					display memory as a saved register set.
/R	expr					display saved register set for pid.
/m	expr [expr]				display mxfer_entry at expr (for expr)
?							show registers and fault
"							comment till end of line.
!	expr					print expression.
_
b	expr					set breakpoint at addr.
b	?						show all breakpoints.
g							continue execution
s							enter single-step-mode.
v							continue from fault via 'stored' fault vector.
V	[expr]					trap fault (default all)
u	[expr]					clear breakpoint at addr, or clear all breakpoints.
U	[expr]					restore fault (default all)
=							continuing, keeping breakpoint

