//------------------------------------------------------------------
//	segvtrap.s
//
//	This example shows how a signal-handler can be used to help 
//	diagnose the cause of a 'Segmentation Violation" exception.
//
//	  	to assemble:  $ as segvtrap.s -o segvtrap.o
//		and to link:  $ ld segvtrap.o -o segvtrap
//
//	programmer: ALLAN CRUSE
//	written on: 15 APR 2007
//------------------------------------------------------------------

	# manifest constants
	.equ	sys_EXIT, 1
	.equ	sys_WRITE, 4
	.equ	sys_SIGNAL, 48
	.equ	SIGSEGV, 11 
	.equ	STDOUT, 1

	.section	.text
_start:	# install our signal-handling function
	mov 	$sys_SIGNAL, %eax	# system-call ID-number
	mov 	$SIGSEGV, %ebx		# signal-number to catch
	lea 	action, %ecx 		# signal-handler address
	int 	$0x80			# invoke kernel service
	or	%eax, %eax		# successfully installed?
	jnz	exit			# no, exit program early

	# setup some recognizable register-values
	mov	$0xAAAAAAAA, %eax
	mov	$0xBBBBBBBB, %ebx
	mov	$0xCCCCCCCC, %ecx
	mov	$0xDDDDDDDD, %edx
	mov	$0xEEEEEEEE, %esi
	mov	$0xFFFFFFFF, %edi
	mov	$0x12345678, %ebp

	# now try to execute a 'privileged' instruction
	hlt				# to trigger a segfault

exit:	# terminate this program
	mov	$sys_EXIT, %eax		# system-call ID-number
	mov	$0, %ebx		# setup our return-code
	int	$0x80			# invoke kernel service


	.section	.data
names:	.ascii	" sig  GS  FS  ES  DS"
	.ascii	" EDI ESI EBP ESP EBX EDX ECX EAX"
	.ascii	" int err EIP  CS EFL ESP  SS"
buf:	.ascii	" nnn=xxxxxxxx \n"
len:	.int	. - buf
msg:	.ascii	"\n [CS:EIP]  "
ops:	.ascii	"xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx \n"
osz:	.int	. - msg


	.section	.text
action:	# this is the entry-point to our signal-handler
	push	%ebp
	mov	%esp, %ebp		# setup stackframe access

	mov	$19, %esi		# initial element-number
nxelt:
	# format the element-name
	mov	names(, %esi, 4), %eax	# lookup element-name
	mov	%eax, buf		# store name in buffer

	# format the element-value
	mov	8(%ebp, %esi, 4), %eax	# lookup element-value
	lea	buf+5, %edi		# point to dest'n field
	call	eax2hex			# convert value to hex

	# write the buffer to standard-output
	mov	$sys_WRITE, %eax	# system-call ID-number
	mov	$STDOUT, %ebx		# device-file ID-number
	lea	buf, %ecx		# address of string
	mov	len, %edx		# length of string
	int	$0x80			# invoke kernel service

	dec	%esi			# decrement element-number
	jns	nxelt			# again if non-negative

	# exhibit the faulting instruction's machine-code
	mov	68(%ebp), %esi		# EIP-image into ESI
	lea	ops, %edi		# point to dest'n buffer
	mov	$15, %ecx		# number of bytes to show
	lea	hex, %ebx		# setup EBX for 'xlat'
	cld				# do forward processing
nxbyt:	lodsb				# instruction-byte into AL
	xor	%ah, %ah		# clear adjacent register
	ror	$4, %ax			# rotate register-pair
	ror	$4, %ah			# rotate upper-register
	xlat				# convert AL to numeral
	stosb				# and store to buffer
	xchg	%ah, %al		# exchange registers
	xlat				# convert AL to numeral
	stosb				# and store to buffer
	inc	%edi			# advance buffer-pointer
	loop	nxbyt			# again for other bytes
	
	# write the buffer to standard-output	
	mov	$sys_WRITE, %eax	# system-call ID-number
	mov	$STDOUT, %ebx		# device-file ID-number
	lea	msg, %ecx		# address of message
	mov	osz, %edx		# length of message
	int	$0x80			# invoke kernel service

	# terminate this program
	jmp	exit			# back to 'bash' shell


hex:	.ascii	"0123456789ABCDEF"	# translation-table

eax2hex: # converts the value in EAX to a hexadecimal string at EDI
	pushal
	mov	$8, %ecx
nxnyb:	rol	$4, %eax
	mov	%al, %bl
	and	$0xF, %ebx
	mov	hex(%ebx), %dl
	mov	%dl, (%edi)
	inc	%edi
	loop	nxnyb
	popal
	ret

	.global	_start
	.end