change checkpoint generation to integrate GDB scripting more cleanly and save UART and PLIC state

This commit is contained in:
bbracker 2022-03-07 17:59:49 -08:00
parent 409dd48706
commit 097301635a
5 changed files with 193 additions and 69 deletions

View File

@ -1,63 +0,0 @@
#! /usr/bin/python3
import sys
if len(sys.argv) != 8:
sys.exit("""Error createGenCheckpointScript.py expects 7 args:
<TCP port number>
<path to vmlinux>
<checkpoint instruction count>
<path to GDB checkpoint state dump>
<path to GDB ram dump>
<checkpoint pc address>
<number of times pc has already been hit before checkpoint>""")
tcpPort=sys.argv[1]
vmlinux=sys.argv[2]
instrCount=sys.argv[3]
statePath=sys.argv[4]
ramPath=sys.argv[5]
checkPC=sys.argv[6]
checkPCoccurences=sys.argv[7]
GDBscript = f"""
# GDB config
set pagination off
set logging overwrite on
set logging redirect on
set confirm off
# Connect to QEMU session
target extended-remote :{tcpPort}
# QEMU Config
maintenance packet Qqemu.PhyMemMode:1
# Symbol file
file {vmlinux}
# Step over reset vector into actual code
stepi 100
# Proceed to checkpoint
print "GDB proceeding to checkpoint at {instrCount} instrs, pc {checkPC}\\n"
b *0x{checkPC}
ignore 1 {checkPCoccurences}
c
print "Reached checkpoint at {instrCount} instrs\\n"
# Log all registers to a file
printf "GDB storing state to {statePath}\\n"
set logging file {statePath}
set logging on
info all-registers
set logging off
# Log main memory to a file
print "GDB storing RAM to {ramPath}\\n"
dump binary memory {ramPath} 0x80000000 0xffffffff
kill
q
"""
GDBscriptFile = open("genCheckpoint.gdb",'w')
GDBscriptFile.write(GDBscript)
GDBscriptFile.close()

View File

@ -19,8 +19,11 @@ fi
checkPtDir="$tvDir/checkpoint$instrs"
outTraceFile="$checkPtDir/all.txt"
interruptsFile="$checkPtDir/interrupts.txt"
rawStateFile="$checkPtDir/stateGDB.txt"
rawUartStateFile="$checkPtDir/uartStateGDB.txt"
uartStateFile="$checkPtDir/checkpoint-UART"
rawPlicStateFile="$checkPtDir/plicStateGDB.txt"
plicStateFile="$checkPtDir/checkpoint-PLIC"
rawRamFile="$checkPtDir/ramGDB.bin"
ramFile="$checkPtDir/ram.bin"
@ -55,7 +58,48 @@ then
echo "It occurs ${occurences} times before the ${instrs}th instr."
# Create GDB script because GDB is terrible at handling arguments / variables
./createGenCheckpointScript.py $tcpPort $imageDir/vmlinux $instrs $rawStateFile $rawRamFile $pc $occurences
cat > genCheckpoint.gdb <<- end_of_script
set pagination off
set logging overwrite on
set logging redirect on
set confirm off
target extended-remote :$tcpPort
maintenance packet Qqemu.PhyMemMode:1
file $imageDir/vmlinux
# Step over reset vector into actual code
stepi 100
shell echo \"GDB proceeding to checkpoint at $instrs instrs, pc $pc\"
b *0x$pc
ignore 1 $occurences
c
shell echo \"Reached checkpoint at $instrs instrs\"
shell echo \"GDB storing CPU state to $rawStateFile\"
set logging file $rawStateFile
set logging on
info all-registers
set logging off
shell echo \"GDB storing UART state to $rawUartStateFile\"
set logging file $rawUartStateFile
set logging on
x/8xb 0x10000000
set logging off
shell echo \"GDB storing PLIC state to $rawPlicStateFile\"
shell echo \"Note: this dumping assumes a maximum of 63 PLIC sources\"
set logging file $rawPlicStateFile
set logging on
# Priority Levels for sources 1 thru 63
x/63xw 0x0C000004
# Interrupt Enables
x/2xw 0x0C020000
# Global Priority Threshold
x/1xw 0x0C200000
set logging off
shell echo \"GDB storing RAM to $rawRamFile\"
dump binary memory $rawRamFile 0x80000000 0xffffffff
kill
q
end_of_script
# GDB+QEMU
echo "Starting QEMU in replay mode with attached GDB script at $(date +%H:%M:%S)"
(qemu-system-riscv64 \
@ -64,12 +108,15 @@ then
-bios $imageDir/fw_jump.elf -kernel $imageDir/Image -append "root=/dev/vda ro" -initrd $imageDir/rootfs.cpio \
-singlestep -rtc clock=vm -icount shift=0,align=off,sleep=on,rr=replay,rrfile=$recordFile \
-gdb tcp::$tcpPort -S \
2>&1 1>./qemu-serial | ./parseQEMUtoGDB.py | ./parseGDBtoTrace.py $interruptsFile | ./remove_dup.awk > $outTraceFile) \
& riscv64-unknown-elf-gdb --quiet -ex "source genCheckpoint.gdb"
1>./qemu-serial) \
& riscv64-unknown-elf-gdb --quiet -x genCheckpoint.gdb
echo "Completed GDB script at $(date +%H:%M:%S)"
# Post-Process GDB outputs
./parseState.py "$checkPtDir"
./parseUartState.py "$rawUartStateFile" "$uartStateFile"
./parsePlicState.py "$rawPlicStateFile" "$plicStateFile"
echo "Changing Endianness at $(date +%H:%M:%S)"
make fixBinMem
./fixBinMem "$rawRamFile" "$ramFile"

View File

@ -0,0 +1,87 @@
#! /usr/bin/python3
import sys, os
################
# Helper Funcs #
################
def tokenize(string):
tokens = []
token = ''
whitespace = 0
prevWhitespace = 0
for char in string:
prevWhitespace = whitespace
whitespace = char in ' \t\n'
if (whitespace):
if ((not prevWhitespace) and (token != '')):
tokens.append(token)
token = ''
else:
token = token + char
return tokens
#############
# Main Code #
#############
print("Begin parsing PLIC state.")
# Parse Args
if len(sys.argv) != 3:
sys.exit('Error parsePlicState.py expects 2 args: <raw GDB state dump> <output state file>')
rawPlicStateFile=sys.argv[1]
outPlicStateFile=sys.argv[2]
if not os.path.exists(rawPlicStateFile):
sys.exit('Error input file '+rawPlicStateFile+'not found')
# Main Loop
with open(rawPlicStateFile, 'r') as rawPlicStateFile:
plicIntPriorityArray=[]
# 0x0C000004 thru 0x0C000010
plicIntPriorityArray += tokenize(rawPlicStateFile.readline())[1:]
# 0x0C000014 thru 0x0C000020
plicIntPriorityArray += tokenize(rawPlicStateFile.readline())[1:]
# 0x0C000024 thru 0x0C000030
plicIntPriorityArray += tokenize(rawPlicStateFile.readline())[1:]
# 0x0C000034 thru 0x0C000040
plicIntPriorityArray += tokenize(rawPlicStateFile.readline())[1:]
# 0x0C000044 thru 0x0C000050
plicIntPriorityArray += tokenize(rawPlicStateFile.readline())[1:]
# 0x0C000054 thru 0x0C000060
plicIntPriorityArray += tokenize(rawPlicStateFile.readline())[1:]
# 0x0C000064 thru 0x0C000070
plicIntPriorityArray += tokenize(rawPlicStateFile.readline())[1:]
# 0x0C000074 thru 0x0C000080
plicIntPriorityArray += tokenize(rawPlicStateFile.readline())[1:]
# 0x0C000084 thru 0x0C000090
plicIntPriorityArray += tokenize(rawPlicStateFile.readline())[1:]
# 0x0C000094 thru 0x0C0000a0
plicIntPriorityArray += tokenize(rawPlicStateFile.readline())[1:]
# 0x0C0000a4 thru 0x0C0000b0
plicIntPriorityArray += tokenize(rawPlicStateFile.readline())[1:]
# 0x0C0000b4 thru 0x0C0000c0
plicIntPriorityArray += tokenize(rawPlicStateFile.readline())[1:]
# 0x0C0000c4 thru 0x0C0000d0
plicIntPriorityArray += tokenize(rawPlicStateFile.readline())[1:]
# 0x0C0000d4 thru 0x0C0000e0
plicIntPriorityArray += tokenize(rawPlicStateFile.readline())[1:]
# 0x0C0000e4 thru 0x0C0000f0
plicIntPriorityArray += tokenize(rawPlicStateFile.readline())[1:]
# 0x0C0000f4 thru 0x0C0000fc
plicIntPriorityArray += tokenize(rawPlicStateFile.readline())[1:]
# 0x0C020000 thru 0x0C020004
plicIntEnable = tokenize(rawPlicStateFile.readline())[1:]
# 0x0C200000
plicIntPriorityThreshold = tokenize(rawPlicStateFile.readline())[1:]
with open(outPlicStateFile, 'w') as outPlicStateFile:
for word in plicIntPriorityArray:
outPlicStateFile.write(word[2:]+'\n')
for word in plicIntEnable:
outPlicStateFile.write(word[2:]+'\n')
for word in plicIntPriorityThreshold:
outPlicStateFile.write(word[2:]+'\n')
print("Finished parsing PLIC state!")

View File

@ -24,7 +24,7 @@ def tokenize(string):
#############
# Main Code #
#############
print("Begin parsing state.")
print("Begin parsing CPU state.")
# Parse Args
if len(sys.argv) != 2:
@ -96,4 +96,4 @@ with open(stateGDBpath, 'r') as stateGDB:
outFile.write(hex(byte)[2:]+'\n')
outFile.close()
print("Finished parsing state!")
print("Finished parsing CPU state!")

View File

@ -0,0 +1,53 @@
#! /usr/bin/python3
import sys, os
################
# Helper Funcs #
################
def tokenize(string):
tokens = []
token = ''
whitespace = 0
prevWhitespace = 0
for char in string:
prevWhitespace = whitespace
whitespace = char in ' \t\n'
if (whitespace):
if ((not prevWhitespace) and (token != '')):
tokens.append(token)
token = ''
else:
token = token + char
return tokens
#############
# Main Code #
#############
print("Begin parsing UART state.")
# Parse Args
if len(sys.argv) != 3:
sys.exit('Error parseUartState.py expects 2 args: <raw GDB state dump> <output state file>')
rawUartStateFile=sys.argv[1]
outUartStateFile=sys.argv[2]
if not os.path.exists(rawUartStateFile):
sys.exit('Error input file '+rawUartStateFile+'not found')
# Main Loop
with open(rawUartStateFile, 'r') as rawUartStateFile:
with open(outUartStateFile, 'w') as outUartStateFile:
uartBytes = tokenize(rawUartStateFile.readline())[1:]
# Stores
# 0: RBR / Divisor Latch Low
# 1: IER / Divisor Latch High
# 2: IIR
# 3: LCR
# 4: MCR
# 5: LSR
# 6: MSR
# 7: SCR
for uartByte in uartBytes:
outUartStateFile.write(uartByte[2:]+'\n')
print("Finished parsing UART state!")