fdbg for Linux x64 help

fdbg for Linux x64 on AMD64
assembler level debugger for user mode 64-bit executable binaries (ELF64)

Thanx to:
Tomasz Grysztar, the author of FASM http://flatassembler.net
alorent, valy for finding disassembler mistakes

Please note that fdbg is compressed with an experimental method.
Use uncompressed executable from src directory if you have any trouble.

00 installation
01 command line parameters
02 first steps (help command, ENTER)
03 running program, exiting fdbg
04 stepping
05 displaying and changing registers
06 displaying and changing code, data, stack
07 software breakpoints
08 hardware breakpoints
09 transport between memory and file
0A debug symbols
0B varia

; ---

00 installation
put fdbg into /usr/bin or into /bin or into $HOME/bin
putting it into directories when path points allows you to invoke it directly
fdbg
and you needn't to include path unlike in other directories
e.g.
/home/guest/fdbg
if you don't have access to directories where the path points, then put it into
the directory with your program which you want to debug and invoke it
./fdbg your_program

; ---

01 shell line parameters

for debug something like:
./convert infile.html outfile.txt -l 80
use this:
fdbg convert infile.html outfile.txt -l 80

You needn't to put ./ before executable name, fdbg does it itself:
fdbg ./convert infile.html outfile.txt -l 80

you can invoke fdbg from other path to, e.g.
fdbg ../convert infile.html outfile.txt -l 80
or
fdbg /convert infile.html outfile.txt -l 80
or
fdbg work/convert infile.html outfile.txt -l 80
or
fdbg ../../work/convert infile.html outfile.txt -l 80

; ---

02 first steps (help command, ENTER)
debuggee means program being debugged
Once you have invoked fdbg to do debugging, fdbg stops at entrypoint (the first
instruction to execute) of the debuggee. If you haven't read this manual, you
mayn't even know how to exit fdbg and most of you tries to do something. If you
give any unknown command, fdbg prints brief help page to the console with all
commands. The first command is help command. Just type:
h
into the console and press ENTER.
If you want to know something about c command, then type:
h c
into the console and press ENTER.
If you want to learn about x command, then type:
h x
into the console and press ENTER.
If you don't type anything and you just press ENTER, then the last command is
repeated. This is usefull especially for displaying code, data, stack.
You just type:
c
and then you only press ENTER several times (till you want).
So try to type:
d
and press ENTER several times for walk through data.
Or type:
e
and press ENTER several times (till you get error message) for walk through the
stack (usefull for everybody who hasn't any image how the stack looks like).
Or type:
s
and press ENTER several times for single stepping through program

; ---

03 running program, exiting fdbg
To run debuggee, type:
g
(it means go!).
Debuggee executes and if it doesn't generate any exception, it terminates and
then fdbg exits. If debuggee generates any exception, then it is stopped at the
address of exception so you may explore why it has happened (you may explore
registers, memory, ...). If your program hasn't debug symbols it may be hard
to indentify where the error in your source code is. Few tricks may be used to
approximate the location of the bug in the code (read later - 0B varia).
Once fdbg exits with termination of the debuggee, you have to repeat shell line
command again if you want to repeat debugging - for beginners: press UP arrow
under bare terminal, ALT + P under Midnight Commander (command mc), ...
There are 2 possibilities how to exit from fdbg without waiting to termination
of the debuggee, commands:
k
l
k means kill, l means leave_to_run.
k kills debuggee and then fdbg exits immediatelly.
l leaves debuggee to run and fdbg exits immediatelly without waiting for
debuggee termination.

; ---

04 stepping
Instead of g command which runs debuggee till its end (or exception), there are
2 other possibilities to run debuggee in steps, not only till its exitting.
Both possibilities execute g command at the end, but they do something before
g command to halt running of debuggee very soon after starting of the g command.
The 2 commands are:
s
t
s means single_step, t means trace_over.
s command sets Trap Flag of the rflags register, t command puts software
breakpoint on the address of the next instruction. After doing it, both execute
run (command g) and then fdbg simple waits for exception triggered by the
debuggee. The reason why both commands do small steps (in contrast of execution
till sys_exit of the debuggee when fdbg does g command) is that running debuggee
triggers very soon exception (SIGTRAP signal, which means exception of
single_step or breakpoint) so the debuggee is halted somewhere in the code and
fdbg is notified about this fact.
The smallest possible step does the s command. The command t may do a bit
bigger steps and it makes sense for instructions call, repz/repnz, loop. For
other instructions you may better use s command, but you needn't to worry about
it, fdbg automatically does command s for other instructions than call rep loop.
The instructions call, repz/repnz, loop may do more instructions and if you
don't want to wait to single step their doing then use t command. Especially
e.g. when rcx register is big enough and you are at e.g. instruction repz stosb
then of course you can do single stepping (command s) for several days but trace
over (command t) is more faster and you may save a lot of time. But sometimes
you may want to single step (s command) several first instructions of repz stosb
and then you finish the instruction with t command.
Sometimes you may want to do several first loops of a loop with s command and at
the end you may finish the loop with t command on the instruction loop.
Once you enter procedure (command s on call), you have to finish it till return.
Using t command inside procedure (=called code) may only prevent to enter
subprocedures which of course may reduce the number of steps till return from
procedure. Using t command on an instruction of call may call the procedure for
a time till procedure executes its instructions (it may last a lot of time
depending of complexity of the procedure, number and kind of instructions to
execute, CPU clock, ...). Using s command on a call instruction enters the
procedure so you have to do more steps till retrurn from the procedure. Using
command t on instruction call doesn't require anything else, you just wait till
return from procedure (it may last nano/microseconds or more depending on
procedure).
Another command to run debuggee in step is the command u (execute until return
from procedure). This command may be used to run debuggee until it returns from
procedure (fdbg tries to find the return address in stack and it may rarely fail
to do it) if you entered the procedure by the command s
I hope you have understood difference between single step and trace over. The
best explanation are excercises, so write some simple programs and try to
compare single steps and trace over and use of return from procedure command:
e.g.

sample0: (finds the end of 0-terminated string)
	lea	rdi,[buf]
	mov	ecx,20h	; maximal string size limit, you may use e.g. ecx,10000h
	mov	al,0
	cld
	repnz scasb
; ...
buf	db	'FASM',0

sample1: (calculates factorial, unoptimized code, only for demonstration)
	mov	ecx,10	; we want factorial of 10
	mov	eax,1
	mov	ebx,1
L0:	mul	ebx
	inc	ebx
	loop	L0

sample2: (nothing usefull, only for demonstration)
	mov	eax,2
	call	procedure
	mov	eax,3
	call	procedure
; ... other code here
procedure:
	add	eax,5
	call	subprocedure
	dec	eax
	call	subprocedure
	ret
subprocedure:
	mov	ecx,eax
	inc	ecx
	mul	ecx
	ret

; ---

05 displaying and changing registers
This is task of command:
r
If you use bare command, then fdbg outputs content of GPR (General Purpose
Registers), RIP (64-bit Instruction Pointer, its name is IP in 16-bit, EIP in
32-bit and in RIP in 64-bit), rflags register, flags.
If you don't want to display so many registers, but you want to display only 1,
then use command r space register_name, e.g.
r rax
r r8
r r15
r rip
r rflags
r zf
(zf means zero flag)
You may use only 64-bit register names, if you want 32,16,8-bit register, you
have to use corresponding 64-bit register name. You may use 1-bit flags (e.g.
cf, zf, sf, ... for Carry Flag, Zero Flag, Sign Flag, ...).
If you want to display other registers (xmm, mm, st), then use the same method
(r space register_name), e.g.
r xmm0
r xmm15
r mm2
r mm7
r st0
r st5
If you want to change register to new value, then use r register_name=new_value
please type this command to display some samples:
h r
(it means Help for R command, avoid to type capitals, fdbg takes strings case
sensitive).
E.g. if you want to set Zero Flag to 1, then use command
r zf=1
If you want to set rflags to 302 (hexa), then use command
r rflags=302
If you want to set rax to 2, then
r rax=2
If you want to set r8 to -1, then
r r8=-1
strings are hexa, hexa values aren't case sensitive, you may use +-
Please note that you may set one register to another by this way, e.g.
r rcx=r11
r rax=rcx-2F5
If you want to set floating point registers, then you have several possibilities
for input values, but you needn't to worry about them. Just enter what you want.
Fdbg just counts the number of entered decimal dots and decides whether value
means hexa value (0 dots), st 80-bit precision (1 decimal dot in st/mm), double
precision (2 dots in xmm because 2 decimal numbers), single precision (4 dots in
xmm because 4 decimal numbers, 2 dots in mm because 2 decimal numbers).
So if you omit a dot for decimal number, then fdbg takes it as hexa number. If
you e.g. type -9 it means decimal number for you but fdbg doesn't encounter any
decimal dot there and it tries to take it as hexa number, but it failes because
+- sign isn't allowed for hexa numbers. So above correct number is:
-9.
or this way:
-9.0
I don't have so much time to do routines more human-like so they are still too
sensitive for inproper input. You may but you needn't to use + for possitive
floatings, e.g. these inputs are the same:
r xmm5=+1. -5.1*10^+21 +546.31 +.21*10^-9
r xmm5=1. -5.1*10^21 546.31 .21*10^-9
Please note that first numbers are put into highest parts of register.
In above sample, the single precision floating +1.0 is put into bits 96-127,
-5.1*10^21 into bits 64-95, +546.31 into bits 32-63, 0.21*10^-9 into bits 0-31
of xmm5 register. That's the same as in hexa input, e.g.
r rax=1234567890abcdef
byte 12 is put into bits 56-63 of rax, ... byte EF into bits 0-7 of rax (=al).

; ---

06 displaying and changing code, data, stack
the syntax is similar, the first letter of the command is:
c
d
e
(c for code, d for data, e for stack)
If you type only this one letter, then the command displays code/data/stack
from current position. Current position is refreshed every step or every
exception in the debuggee for code and stack. Code is displayed from RIP
(Instruction Pointer), stack from RSP (Stack Pointer). Pointer for data isn't
refreshed. RIP is used for the first displaying of data and pointer is refreshed
to the end of previously displayed memory. Pointer for displaying code/stack is
refreshed to the end of displayed instructions/stack qwords after every command:
c
e
So if you want to display more than default few lines of code, then use command
repeatedly (in fact of using ENTER, you need only at the first time to type the
command:
c
and then for repeating just press ENTER.
You may allways reset pointers to the default by this commands:
c rip
e rsp
This resetting is done every single_step/trace_over/exception_during_execution.
If you want do dump data e.g. from address which is currently in rdi register,
then type this:
d rdi
d
and then only press ENTER for repeating last command.
If you want to change instruction/data/stack then use command:
m
This command requires more input parameters, not the only one letter m.
Since fdbg doesn't have assembler engine (has only disassembler), you can't
enter new instruction to assemble in code. You can only manually enter
corresponding hexa bytes and then verify instruction by command c.
You may enter only hexa values or strings. Strings are enclosed in " or '
e.g. 'Hello!'
if you want string "Hello baby!" then enclose the whole string in the only one
remaining choice of enclosing:
'"Hello baby!"'
If your string contains e.g. ' then enclose it using "
"isn't"
Hexa numbers aren't case sensitive, but you can't use signs +- so if you want to
put -3 you have to use hexa value FFFFFFFFFFFFFFFD or fffffffffffffffd
Address to edit is in brackets []. You may use hexa values or registers or
combination of register-+value
Type character = between brackets and new value to set.
For hexa inputs, put size of desired destination before brackets
Allowed sizes are b w d q for byte word dword qword.
You mustn't put size for string input - size is determined by the size of string
for samples, type command
h m
other examples:
m [4020fC]="didn't"
m d [rax-89A52]=5
m w [rsp+20]=a1a2
m q [100001013]=3ffd0f
This sample is mistake but fdbg truncates the value:
m b [rip]=4190
4190 exceedes value of a byte, fdbg truncates it and takes only low byte of the
word, so byte 90 is put to current address at rip.
fdbg doesn't warn you about truncating.
Please note about order in word/dword/qword
this dword input means:
fed531f0
f0 is the lowest byte of dword
31f0 is the low word of dword
fe is the highest byte of dword
fed5 is the high word of dword
when above input is written to an address, then the lowest byte is written into
the address, the highest byte is written into address+3, the high word into
address+2
so the dump of address
d address
looks:
...(address)... f031d5fe
Another sample:
m q [rdi]=1234567890abcdef
then the dump of data looks:
d rdi
...(address)... efcdab90-78563412-...

Data are displayed as bytes, but stack as qwords, so this sample:
m q [rsp]=1234567890abcdef
does this (displaying stack from rsp):
e rsp
...(address)... 1234567890abcdef

and displaying data from rsp looks:
d rsp
...(address)... efcdab90-78563412-...

It means the same, but data and stack displaying style is different (data are
displayed as string of hexa bytes, stack as hexa qwords).

Note for command m
You needn't to worry whether there is any sw bp in written region.
fdbg handles it so sw breakpoints stay in code and new values at sw bp positions
are only updated in fdbg breakpoint data structures (to be replaced later at sw
bp trigger).

; ---

07 software breakpoints
Software breakpoint means that byte CC (hexa 0CCh) is put into the code. Byte CC
is instruction of breakpoint (like 50 means push rax). Its size of only 1 byte
allows it to overwrite any instruction even the smallest possible instructions
of 1 byte (like above 50 = push rax). After putting software breakpoint into the
debuggee and then allowing the debuggee to run (command g), instructions of
debuggee execute. If instruction of breakpoint on replaced instruction executes,
it causes an exception so debuggee is stopped at that address and fdbg is
notified about it. At that point you can explore and modify memory and registers
of the debuggee or allow it to run again from this point.
Note that fdbg for Linux x64 supports only one-shot sw bp, it means once the
breakpoint is triggered, fdbg immediatelly restores the original byte at the
position of breakpoint. It is possible to think about permanent breakpoints
(which stay in the code after their trigger), but I don't have so much time to
do simulation routines for doing this - 1. sw bp trigger - 2. sw bp stays in the
code - 3. you execute run again (command g) but fdbg must restore the byte at sw
bp address, then fdbg must execute only single_step or trace_over it depends on
some things... - 4. then fdbg must write sw bp again - 5. then fdbg is allowed
to continue what you wanted to do in step 2.
(Yeah, I have done it under fdbg for win64, but I costed too much time so if you
need it ultimately in Linux then try to port it from sources of fdbg for win64.)
Well... once temporary (=one-shot) breakpoint is triggered, it is removed from
the code immediatelly to allow the code to continue after your request for
resuming it from the stop. This is the way how it is done by fdbg:
1. temporary sw bp triggers -> 2. debuggee is stopped -> 3. fdbg does RIP-1
(this is because one-byte instruction 0CCh was executed so RIP is pointing one
byte after begin of original instruction on the position of sw bp) -> 3. fdbg
removes sw bp (=restores the original byte at sw bp) -> 5. fdbg waits to you
Without step 4. there isn't any possibility to continue execution of the code.
Without step 4. you would be stopped definitely at the address of sw bp. The
only one choice to continue if step 4. weren't done would be to increase RIP to
RIP+1 but then you would loose the first byte of instruction which leads to
mess and undefined instruction (and perhaps shift of first bytes of following
instructions thus their damaging).
The warning about breakpoints for beginners !!!
You have to put breakpoint at the first byte of an instruction. Putting it
elsewhere is great mistake because then breakpoint isn't triggered but it only
damages the instruction by overwriting its opcode somewhere in its middle !!!
Use command c before you put breakpoint anywhere to see addresses of
instructions !!!
Syntax for put sw bp is simple, b address , e.g.
b 40113f
b start
b procedure5+20
b rip+20
b rdi-48
b rax
The existence of sw bp in the code is marked by letter b between address and
instruction when displaying code by command c (read later - 0B varia).
The existence of sw bp in data dump (command d) is hidden, fdbg simulates dump
of bytes with original byte at breakpoint position. Even you overwrite byte at
address of breakpoint, you don't damage anything, fdbg handles it well (it only
looks into arrays of data of breakpoints whether there isn't any breakpoint at
that address and when there is a breakpoint there, then fdbg doesn't overwrite
breakpoint in debuggee, fdbg just updates the value of the original byte to be
replaced in the array of data of breakpoint - fdbg currently stores only 2
values in array - address of breakpoint, value of original byte at that address)
Please don't forget this fact!!! Existence of the sw bp is visible only in the
code (command c) but its existence in the data (command d) is hidden. It is much
more complicated to hide existence in the data than not to hide it, but I think
it is better because when you are looking into the data you are supposed not to
try to find breakpoints.
Use command b or command a without any parameter to list breakpoint(s):
b
a
it shows you a list of breakpoint(s) which is clean of course till you put any
breakpoint into the code.
Command a is used for delete breakpoint(s), its syntax is the same as command b.
so if you put any breakpoint using command:
b 1000000C3
then to remove it, use command:
a 1000000C3
Note that once one-shot sw bp is triggered, it is removed immediatelly, it
disappears from the list of breakpoints and you can't to remove it anymore.
Well... once you put one-shot sw bp into the code, it stays there till its
triggering or till its removing by command a (or till sys_exit when debuggee
exits and frees memory occupied by itself). There may be more breakpoints so
you may be stopped somewhere in the code and at that point you are allowed to
delete or put other breakpoints. You can't delete/put sw bp in the time when
debuggee runs (even you can't do anything else than press CTRL+C to kill fdbg
and debuggee).

note2: sw bp overwrites memory, so it is shared among all threads belonging
to the process (any thread of process may hit it once it is set, unlike hw bp)

; ---

08 hardware breakpoints

Hardware breakpoint is done by setting debug registers of CPU - yeah registers,
unlike software breakpoint overwrites 1 byte of MEMORY.
The big disadvantage in comparison with sw bp is limited number of debug
registers. They are 16 dr in long mode, but you can use only 4 hw bp.
Well, that is the only one disadvantage of hw bp. Advantages are:
1. of course you can use hw bp for trigger when execute instruction, but you
may use it for catch access to memory (read/write) (sw bp aren't able to
detect access to memory, sw bp are triggered on instruction execution only).
2. you don't modify memory, so you can beat some antidebugs, or you are allowed
to e.g. calculate correct checksum of actually executed code, e.g.
; your program
crc_data_start:
; header ...
; code
entry_point:
routine_for_calculate_crc:
mov edx,0
mov ecx,0
lea rsi,[crc_data_start]
lea rdi,[crc_to_verify]
cld
L0:
lodsd
xor edx,eax
rol edx,1
ror eax,3
add ecx,eax
cmp rsi,rdi
jc L0
cmp [rdi],edx
jnz code_damaged_possible_virus
cmp [rdi+4],ecx
jnz code_damaged_possible_virus
; code
; data
;...
align 4
crc_to_verify: dd crc0, crc1

If you use sw bp in above crc routine, you can't achieve correct crc, but if you
use hw bp with execute attribute at e.g. instruction cmp [rdi],edx then no
memory is modified and you get correct crc.

The syntax to set hw bp is
x flag type size address
flag may be:
p permanent (not erased after it hits, you must erase it itself)
t temporary (one-shot, erased automatically after it hits)
type may be
e which means executable
r read+WRITE
w write (but not read)
size may be
b
w
d
q
which means byte/word/dword/qword
address must be hexa value
size for executable type must be byte (other choice is denied) so the size
mustn't be in command (fdbg places size of 1 byte automatically for type e)
samples:
x p e 4010c2
the breakpoint triggers when RIP reaches address 4010c2 (instruction on the
address isn't executed, hw bp triggers when RIP=address before execution),
the breakpoint stays in debug registers after it hits

x t r q 405130
this breakpoint triggers only once when writing to or reading from memory
4050130-4050137 (Note r means WRITE+READ)

x p w b 41a2e5
this breakpoint triggers always when writing to memory 41a2e5

these commands show you a list of hw bp:
x
y
for remove hw bp use command y followed by the number of hw bp (not address!!!)
e.g.
y 0
deletes hw bp No. 0
use bare command
y
to decide which of max 4 possible hw bp you want to delete
(the reason to use syntax y No. and not to use syntax y address is that you may
combine more hw bp at the same address, so then you may want to delete hw bp No.
not hw bp at some address because they are more watching the same address).

Note about hardware breakpoints.
you can set 3 types of hw bp:
e execute, break on instruction execution only (fetching instruction)
w write, break on data writes only
r read/write, break on data reads or writes but not instruction fetches

Note that
r
means read/write, not only read !!!

second note about hw bp:
e has 1 byte size exactly, other sizes are denied
r as well w may be byte/word/dword/qword and address must be aligned on the size
for word align 2, for dword align 4, for qword align 8
if you forget it, CPU itself alignes the address without warning
so, if you put e.g.
x t r q 40120F
you hope, that you catch access to bytes 40120F-401216, but you aren't right,
because CPU alignes value to 401208 and you catch R/W access to 401208-40120F
Maybe I'll add warning message into fdbg, but today you aren't warned.
To catch address 40120F-401216 you have to use 2 hw bp
x t r b 40120F
x t r q 401210
and you catch not only 40120F-401216 but unwanted address 401217 too.
or 4 hw bp
x t r b 40120F
x t r d 401210
x t r w 401214
x t r b 401216
and you catch exactly 40120F-401216

note3: hw bp uses registers, so it is private for thread, it doesn't belong to
other threads of process, other thread can't hit it (unlike sw bp)

note4: hw bp by instruction execution occures before the instruction executes
             (instruction pointer is at the start of the instruction)
       hw bp by memory access (read/write, write) occures after the instruction
             completes (after the memory is read or written, instruction
	     pointer points to begin of the following instruction)

note5: debuggee is forced to pas through permanent hw bp by setting rflags.RF=1

note6: you can't pass through permanent hw bp at older kernels - they seem to
       refuse set rflags.RF=1 (RF stays 0 after any attempt to write 1 there)
       to detect that, try the command pair:
       r rflags=10202
       r rflags
       kernel which sets RF correctly gives output:
       rflags=0000000000010202
       if now rflags=0000000000000202 then your kernel doesn't set RF properly
       in this case, edit the file /usr/src/linux/arch/x86_64/kernel/ptrace.c
       find the line looking like:
       #define FLAG_MASK 44dd5UL
       add 10000h to the mask (e.g. 54dd5UL in the above sample), recompile
       kernel, add the new kernel to boot loader and reboot it

; ---

09 transport between memory and file

You can save memory into a file and load memory from a file using command:
f
the syntax is
f l/s memstart memend/+size
l/s choose only one of: l to load mem from file, s to save mem into file
memstart hexa address, you can't use symbols, registers either
memend/+size hexa number if you type it with + it means size, without + it means
end of memory block to save (saves bytes upto this address, doesn't save byte
at memend address !!!)

to save 1C8h bytes from address 1000000b0h into file dump0.bin:
f s dump.bin 1000000b0 +1c8

to save memory 1000000B0h-100000277h into dumpmem.bin (usaved_mem=100000278h):
f s dumpmem.bin 1000000b0 100000278
again and again, 100000278h means that last saved byte is at mem 100000277h

to load a0h bytes from file memdump into address 1000001A0h:
f l memdump 1000001a0 +a0

to load bytes from file memdump into address 1000001A0h-10000023fh
(thus unsaved memory begins at 100000240h:
f l memdump 1000001a0 100000240

Note, if you save memory, the memory dump is free of sw bp. When loading from a
file you needn't to worry whether there is any sw bp in written region.
fdbg handles it so sw breakpoints stay in code and new values at sw bp positions
are only updated in fdbg breakpoint data structures (to be replaced later at sw
bp trigger).

; ---

0A debug symbols

Debug symbols are big helpers to determine addresses in code and data.
Refer to the samples how to build-in debug symbols into program.
For every address you can substitute hexa value with the symbol.
You are allowed to do it in commands:
c d e m b a x y (code data stack modify_mem sw_bp sw_bp_del hw_bp hw_bp_del)

Samples:
imagine this source:
; code:
start:
; ...
call procedure07
; ...
sys_exit

procedure07:
; ...
mov eax,dword [hash_tmp]
; ...
ret

; data:
; ...
hash_tmp:	dd	81234567Ah
input_string	db	'debko',0

if you want to put breakpoint at procedure07 and this label is built in
your program, then you needn't to worry about the address of the procedure and
you simple do it in this way:
b procedure07

if you want to watch reading+writing to the dword at the label hash_tmp, then:
x r q hash_tmp

if you want to dump code 14Ah after the begin of procedure07 then:
c procedure07+14A

if you want to dump data 0C8h bytes before the label hash_tmp, then:
d hash_tmp-C8

if you want to modify string 2 bytes after label input_string, then e.g.
m [input_string+2]='ment'
m b [input_string+6]=0

Debug symbols are displayed in disassembled code, e.g. command c proc_hash00
00000001000001C0    proc_hash00: mov rax,[rdi+rcx*8] ; [0000000100010200=input_pointers]=0000000100010480=subproc13

; ---

0B varia

you can notice RIP and sw bp in the code dump by something between address and
instruction, e.g.
00000001000000B0  > cld
00000001000000B1    mov ecx,[rsp]
00000001000000B4    dec ecx
00000001000000B6    jz 00000001000013E9
00000001000000BC b  lea rdi,[000000010000A7A0]
                 this b means software breakpoint
> in the first line means RIP on current instruction
b means software breakpoint

There is a choice that debuggee execution lasts for a long time till breakpoint
or exception triggers. fdbg doesn't inform you about debuggee status yet. The
only sign that debuggee is still running is that you haven't any response for
commands, e.g.
if you type command
r rip
then fdbg doesn't display content of RIP register till debuggee runs.
You can't do anything else than press CTRL+C to kill fdbg and debuggee (but then
everything is lost and you have to begin debugging again, put sw bp again, ...).

Please note that commands are case sensitive (as everything in Linux is)
so this command gives error resulting into printing of the basic help page:
H R
correct is:
h r
even register names are case sensitive
the only one insensitive case are hexa values, e.g. 1D5b is the same as 1d5B
You must use only 1 space between 2 strings (if you use 2 spaces fdbg displays
message about bad syntax or bad input value).

If your program doesn't support debug symbols, it may be hard to indentify where
the error causing exception (bug) in your source code is (especially when your
executable has big code). Few tricks (2-3) may be used to approximate the
location of the bug in the code.
You are notified about the signal causing stop. The presence of bug (exception)
has these signs:
- you ordered fdbg to run the debuggee but it stops so fdbg doesn't exit
- you try to continue run (command g) or single_step (command s) or trace_over
  (command t) and to display registers (command r) and to display code
  (command c) again and again but nothing changes (even RIP register)
Notice the address of bug by command c, command r rip (necessary for 9.2 method)
and the instruction causing bug.
Try to display registers with command r
Try to do the same as the instruction does, e.g. if instruction is mov eax,[rsi]
then try to dump data
d rsi
If fdbg notifies you with message:
Error PTRACE/PEEKTEXT read code/data at address 00000001010543d8
then the result is that bug wants to access an unmapped memory.
When instruction is e.g. mov [rdi],eax
and this command
d rdi
gives correct memory dump, then the possible explanation is that you want to
write to the memory which is read-only but not readwrite.
If buggy instruction is e.g.
movdqa xmm0,[rsi]
movaps xmm0,[rsi]
movapd xmm0,[rsi]
and command
d rsi
gives good-looking result, then rsi isn't aligned 16, so try command:
r rsi
If buggy instruction is:
div ecx
then try command:
r rcx
whether ecx isn't 0 (divide by zero).

Well 2-3 possible choices how to find the position of bug in the source:

9.0 try to type something like:
c
c rip-20
If there is any exotic instruction with rare appearance in your sources then you
may find it easily by search function of a text editor. Please keep in mind that
command:
c rip-20
may give same exotic instruction if the address at rip-20 wraps somewhere e.g.
inside of 4-byte instruction at rip-22 (you can't know whether e.g. 5th
instruction back begins at address rip-20 or at address rip-21 or rip-22, ...)

9.1
Put one of these 2 equal instruction:
int3
db 0cch
into your source code, recompile it and run under fdbg again. Watch whether
breakpoint or bug appears the first. If breakpoint appears the first, then move
it further and further from the entrypoint to go closer of buggy instruction
till bug causes the exception as the first (=before breakpoint). Then the bug is
between current and previous position of int3 = db 0cch in the source code.

9.2
Put instruction:
lea rax,[any_label_from_source] ; 7-bytes instruction
at entrypoint (the first instruction to execute) of the program.
Recompile the program.
Load under fdbg - only load, nothing more, e.g. fdbg ./program
Use command:
g
as the first command after loading program into fdbg.
Compare the address after lea instruction with the address of bug.
The first instruction is transformed into an address so now you can compare
whether the label address is below, above and how much close to the address of
the bug. The increasing of code by 7 bytes by putting lea rax,[...] isn't much
important, but may cause rare disappearing of the bug (especially may cause
align 16 of accessing xmm registers with instructions: movdqa, movaps, movapd
when they read from the code and not from aligned data - e.g. by calculating
self-crc check of the code...)
Then change lea rax,[any_label_from_source] to another label (or the name of a
procedure), do the same and watch output of command:
g
whether hexa value in lea rax,[hexa_value] is closer to the address of the bug.

The trick with putting
int3
db 0cch
into the source may be used as a way of quick and direct (without long stepping)
jump into the code supposed not to do what you want for it to do.
Just put:
int3
or put:
db 0CCh
into your source at the begin of instructions you want to examine, then
recompile your program, load under fdbg and use command:
g
Execution stops after breakpoint trigger in your code at required position.
Don't forget to remove int3 = db 0CCh and recompile the program before you
release it to usage. Else program generates exception because there isn't any
debugger as its parent to catch the exception generated by db 0CCh (int 03).

; ---

If you weren't experts for debugging I hope you already are. But I know that
after the first reading of this manual you may have bigger mess in you brain
than before.

epilogue:
mov [have_I_understood],0
mov ecx,10 ; number may vary and is dependend on your patience
L0:
call read_fdbg_manual_and_try_to_understand_it
cmp [have_I_understood],1
loopnz L0
jnz fuck_you_fdbg


usefull links:
flat assembler Linux forum
http://board.flatassembler.net/forum.php?f=4
google search:
http://www.google.com/search?q=fdbg+linux+AMD64+feryno
my home page with assembler samples and projects (Linux x64, win64)
http://feryno.host.sk/index.html
if freehosting is off, try www.google.com with keyword Feryno
or try to find me on fasm board
http://board.flatassembler.net

my nick is
Feryno

I'm only assembler fan, self-learner. Don't ask me professional questions.
I want to support asm coding under great AMD64 platform.
I completely left old 32-bit world in the middle of year 2005.

Please report bugs and disassembler mistakes to me, possible ways are:
- mail address
  name@mailserver
  name db 'feryno'
  mailserver db 70h,6Fh,62h,6Fh,78h,2Eh,73h,6Bh
  (antimalware protection, human brain is necessary to solve mail address)
- ICQ 257740061
- http://board.flatassembler.net  flatassembler forum, PM to feryno
  http://board.flatassembler.net/profile.php?mode=viewprofile&u=1297
