//----------------------------------------------------------------- // dumpregs.s // // This file defines an assembly language procedure that can // be called from a separate program in order to display the // current values in CPU registers using hexadecimal format. // (The 'pushal' instruction is used to store the registers' // values on the stack (where they can be accessed as a list // of 32-bit values in a prescribed order), and then 'popal' // is used to restore those register-values before exiting.) // // assemble using: $ as dumpregs.s -o dumpregs.o // then link with: $ ld .o dumpregs.o -o // // programmer: ALLAN CRUSE // written on: 13 FEB 2008 //----------------------------------------------------------------- ' # equates for the symbolic constants we will use .equ sys_write, 4 # ID-number of system-call .equ dev_stdout, 1 # ID-number of device-file .section .data hex: .ascii "0123456789ABCDEF" # the hexadecimal numerals buf: .ascii " rrr=xxxxxxxx \n" # template for output-line len: .int . - buf # length of an output-line reg: .ascii " EDI ESI EBP ESP EBX EDX ECX EAX EIP" num: .int (. - reg) / 4 # number of register-names .section .text # # This 'helper function' gets called repeatedly to convert a value # found in the EAX register into its representation as a string of # hexadecimal digit-characters at the location in memory beginning # at the address found in the EDI register. # eax2hex: pushal # preserve CPU registers mov $8, %ecx # setup the digit-count nxnyb: rol $4, %eax # get next nybble in AL mov %al, %bl # copy the nybble to BL and $0x0F, %ebx # isolate nybble's bits mov hex(%ebx), %dl # lookup nybble's digit mov %dl, (%edi) # write digit to buffer inc %edi # advance buffer-index loop nxnyb # and do another nybble popal # restore saved registers ret # then return to caller # # Here is our code for the 'public' procedure which displays the # current values in certain CPU registers in hexadecimal format. # dumpregs: pushal # preserve CPU registers mov $0, %esi # initial array-index nxelt: # setup the next register-name in our output-buffer mov reg(, %esi, 4), %eax # fetch next register-name mov %eax, buf # store that register-name # setup the next register-value in our output-buffer mov (%esp, %esi, 4), %eax # fetch next register-value mov $buf+5, %edi # point to buffer-position call eax2hex # and convert to hex-string # display the output-buffer's contents on the screen mov $sys_write, %eax # ID-number for system-call mov $dev_stdout, %ebx # ID-number for device-file mov $buf, %ecx # address of message-string mov len, %edx # length for message-string int $0x80 # invoke kernel service # get ready to reenter this loop if any more values remain inc %esi # advance the array-index cmp num, %esi # all registers displayed? jl nxelt # not yet, then show another popal # else recover saved registers ret # and return control to caller .global dumpregs # make name visible to linker .end # no further code to assemble