; --------------------------------------------------------------------------------
; @Title: Segv Script (Linux Awareness)
; @Description:
; Script to investigate segmentation violations and other faults
; see Linux Awareness Manual, chapter 
;     "Debugging Linux"->"Trapping Segmentation Violation"
;
; Call this script to set the appropriate breakpoints
; and call it again to set the register set to the place
; where the fault happened.
;
; The registers are set temporarily; as soon as debugging
; is continued (Step, Go, ...), the original registers
; are restored.
;
; see arch/ppc/mm/fault.c
;
; @Keywords: Linux segv awareness
; @Author: DIE
; @Copyright: (C) 1989-2019 Lauterbach GmbH, licensed for use with TRACE32(R) only
; --------------------------------------------------------------------------------
; $Id: segv.cmm 4125 2019-03-22 17:16:46Z kjmal $   
 
 LOCAL &bad_area &die &mcheck
 GLOBAL &regvar
 
 ; segmentation violation (bad_area)
 IF sYmbol.EXIST(bad_area)
   &bad_area=ADDRESS.OFFSET(bad_area)
 ELSE IF sYmbol.EXIST(t32_bad_area)              ; see documentation
   &bad_area=ADDRESS.OFFSET(t32_bad_area)
 ELSE
 (
    PRINT "label ""bad area"" not found."
    ENDDO
 )
 Break.Set &bad_area
 
 ; kernel oops (die)
 &die=ADDRESS.OFFSET(die\1)     ; 1 line more for locals setup
 Break.Set &die
 
 ; kernel panic
 Break.Set panic
 
 ; if halted on segmentation violation (bad_area)
 IF Register(pc)==&bad_area
 (
    IF sYmbol.EXIST(is_write)
    (
      IF Var.VALUE(is_write)!=0
        &access="write to"
      ELSE
        &access="read from"
    )
    ELSE
      &access="access"
    PRINT "failed to &access 0x" Var.VALUE(address) " at 0x" Var.VALUE(regs.nip)
    &regvar="regs"
    GOSUB swap_registers
    ENDDO
 )

 ; if halted on kernel oops (die)
 IF Register(pc)==&die
 (
    PRINT Var.STRing(str) " at 0x" Var.VALUE(fp.nip)
    &regvar="fp"
    GOSUB swap_registers
    ENDDO
 )

 ENDDO


swap_registers:

 ; set register set temporarily to faulty state

 LOCAL &r0  &r1  &r2  &r3  &r4  &r5  &r6  &r7 
 LOCAL &r8  &r9  &r10 &r11 &r12 &r13 &r14 &r15
 LOCAL &r16 &r17 &r18 &r19 &r20 &r21 &r22 &r23
 LOCAL &r24 &r25 &r26 &r27 &r28 &r29 &r30 &r31
 LOCAL &lr  &cr  &ip  &msr &ctr &xer
 LOCAL &i

 ; first get all register values from local variable "regs" or "fp"

 &i=0.
 WHILE &i<32.
 (
   ; collect all gpr registers to script variables &r0-&r31
   &ic=STRing.CUT("&i",-1)   ; to cut trailing dot
   &r&ic=Var.VALUE(&regvar.gpr[&ic]) ; &r0=v.v(rags.gpr[0])
   &i=&i+1
 )
 &lr=Var.VALUE(&regvar.link)
 &cr=Var.VALUE(&regvar.ccr)
 &ip=Var.VALUE(&regvar.nip)
 &msr=Var.VALUE(&regvar.msr)
 &ctr=Var.VALUE(&regvar.ctr)
 &xer=Var.VALUE(&regvar.xer)

 ; second write values into registers temporarily

 &i=0.
 WHILE &i<32.
 (
   &ic=STRing.CUT("&i",-1)  ; to cut trailing dot
   &&value=&r&ic            ; && for recursive macro parsing
   Register.Set r&ic &value /Task Temporary  ; r.s r0 &r0
   &i=&i+1
 )
 Register.Set msr &msr /Task Temporary
 Register.Set ctr &ctr /Task Temporary
 Register.Set lr  &lr  /Task Temporary
 Register.Set xer &xer /Task Temporary
 Register.Set cr  &cr  /Task Temporary
 Register.Set ip  &ip  /Task Temporary

 RETURN
