overhaul of debugging info printing

float_support
Anton Lydike 3 years ago
parent d0c5abe845
commit d09b7a5cb1

@ -1 +1 @@
pyelftools~=0.27 pyelftools~=0.27

@ -19,4 +19,5 @@ class RunConfig:
# allowed syscalls # allowed syscalls
scall_input: bool = True scall_input: bool = True
scall_fs: bool = False scall_fs: bool = False
verbosity: int = 0

@ -6,8 +6,6 @@ import time
def _window_loop(textIO: 'TextIO'): def _window_loop(textIO: 'TextIO'):
#textIO.set_sg_window(None)
#return
try: try:
import PySimpleGUI as sg import PySimpleGUI as sg
@ -30,10 +28,9 @@ def _window_loop(textIO: 'TextIO'):
col.contents_changed() col.contents_changed()
except ImportError: except ImportError:
print("[TextIO] module works best with PySimpleGui!") print("[TextIO] window disabled - please install PySimpleGui!")
textIO.set_sg_window(None) textIO.set_sg_window(None)
class TextIO(IOModule): class TextIO(IOModule):
def __init__(self, addr: int, buflen: int = 128): def __init__(self, addr: int, buflen: int = 128):
super(TextIO, self).__init__(addr, buflen + 4) super(TextIO, self).__init__(addr, buflen + 4)

@ -6,7 +6,7 @@ SPDX-License-Identifier: MIT
from .Config import RunConfig from .Config import RunConfig
from .Executable import Executable, LoadedExecutable, LoadedMemorySection, LoadedInstruction, MemoryFlags from .Executable import Executable, LoadedExecutable, LoadedMemorySection, LoadedInstruction, MemoryFlags
from .helpers import align_addr from .helpers import align_addr, int_from_bytes
from .Exceptions import OutOfMemoryException, InvalidAllocationException from .Exceptions import OutOfMemoryException, InvalidAllocationException
from .colors import * from .colors import *
from typing import Dict, List, Tuple, Optional from typing import Dict, List, Tuple, Optional
@ -109,7 +109,8 @@ class MMU:
raise InvalidAllocationException('Invalid size request', name, req_size, flag) raise InvalidAllocationException('Invalid size request', name, req_size, flag)
if req_size > self.max_alloc_size: if req_size > self.max_alloc_size:
raise InvalidAllocationException('Cannot allocate more than {} bytes at a time'.format(self.max_alloc_size), name, req_size, flag) raise InvalidAllocationException('Cannot allocate more than {} bytes at a time'.format(self.max_alloc_size),
name, req_size, flag)
base = align_addr(self.first_free_addr) base = align_addr(self.first_free_addr)
size = align_addr(req_size) size = align_addr(req_size)
@ -203,6 +204,9 @@ class MMU:
if symb in b.symbols: if symb in b.symbols:
print(" Found local symbol {}: 0x{:X} in {}".format(symb, b.symbols[symb], b.name)) print(" Found local symbol {}: 0x{:X} in {}".format(symb, b.symbols[symb], b.name))
def read_int(self, addr: int) -> int:
return int_from_bytes(self.read(addr, 4))
def __repr__(self): def __repr__(self):
return "MMU(\n\t{}\n)".format( return "MMU(\n\t{}\n)".format(
"\n\t".join(repr(x) for x in self.sections) "\n\t".join(repr(x) for x in self.sections)

@ -8,6 +8,7 @@ import typing
from .Registers import Registers from .Registers import Registers
from .colors import FMT_DEBUG, FMT_NONE from .colors import FMT_DEBUG, FMT_NONE
from .Executable import LoadedInstruction from .Executable import LoadedInstruction
from .helpers import *
if typing.TYPE_CHECKING: if typing.TYPE_CHECKING:
from . import * from . import *
@ -36,6 +37,9 @@ def launch_debug_session(cpu: 'CPU', mmu: 'MMU', reg: 'Registers', prompt=""):
else: else:
mmu.dump(what, *args, **kwargs) mmu.dump(what, *args, **kwargs)
def dump_stack(*args, **kwargs):
mmu.dump(regs.get('sp'), *args, **kwargs)
def ins(): def ins():
print("Current instruction at 0x{:08X}:".format(cpu.pc)) print("Current instruction at 0x{:08X}:".format(cpu.pc))
return mmu.read_ins(cpu.pc) return mmu.read_ins(cpu.pc)

@ -9,7 +9,7 @@ from .ElfLoader import ElfInstruction, ElfLoadedMemorySection, InstructionAccess
from ..decoder import decode from ..decoder import decode
from ..IO.IOModule import IOModule from ..IO.IOModule import IOModule
from .privmodes import PrivModes from .privmodes import PrivModes
from ..colors import FMT_ERROR, FMT_NONE from ..colors import FMT_ERROR, FMT_NONE, FMT_MEM
import json import json
from functools import lru_cache from functools import lru_cache
@ -117,3 +117,10 @@ class MemoryImageMMU(PrivMMU):
if addr >= val: if addr >= val:
return "{}{:+x} ({}:{})".format(sym, addr - val, sec.owner, sec.name) return "{}{:+x} ({}:{})".format(sym, addr - val, sec.owner, sec.name)
return "{}:{}{:+x}".format(sec.owner, sec.name, addr - sec.base) return "{}:{}{:+x}".format(sec.owner, sec.name, addr - sec.base)
def symbol(self, symb: str):
print(FMT_MEM + "Looking up symbol {}".format(symb))
for owner, symbs in self.debug_info['symbols'].items():
if symb in symbs:
print(" Hit in {}: {} = {}".format(owner, symb, symbs[symb]))
print(FMT_NONE, end="")

@ -83,11 +83,7 @@ class PrivCPU(CPU):
if isinstance(ex, LaunchDebuggerException): if isinstance(ex, LaunchDebuggerException):
self.launch_debug = True self.launch_debug = True
self.pc += self.INS_XLEN self.pc += self.INS_XLEN
else:
print(FMT_ERROR + "[CPU] exception caught at 0x{:08X}: {}:".format(self.pc - 1, ins) + FMT_NONE)
print(ex.message())
if self.conf.debug_on_exception:
self.launch_debug = True
if self.exit: if self.exit:
print() print()
print(FMT_CPU + "Program exited with code {}".format(self.exit_code) + FMT_NONE) print(FMT_CPU + "Program exited with code {}".format(self.exit_code) + FMT_NONE)
@ -114,7 +110,7 @@ class PrivCPU(CPU):
def run(self, verbose: bool = False): def run(self, verbose: bool = False):
print(FMT_CPU + '[CPU] Started running from 0x{:08X} ({})'.format(self.pc, "kernel") + FMT_NONE) print(FMT_CPU + '[CPU] Started running from 0x{:08X} ({})'.format(self.pc, "kernel") + FMT_NONE)
self._time_start = time.perf_counter_ns() // self.TIME_RESOLUTION_NS self._time_start = time.perf_counter_ns() // self.TIME_RESOLUTION_NS
self._run(verbose) self._run(self.conf.verbosity > 1)
def _init_csr(self): def _init_csr(self):
# set up CSR # set up CSR
@ -162,8 +158,6 @@ class PrivCPU(CPU):
def _handle_trap(self, trap: CpuTrap): def _handle_trap(self, trap: CpuTrap):
# implement trap handling! # implement trap handling!
self.pending_traps.append(trap) self.pending_traps.append(trap)
print(FMT_CPU + "Trap {} encountered at {} (0x{:x})".format(trap, self.mmu.translate_address(self.pc), self.pc) + FMT_NONE)
def step(self, verbose=True): def step(self, verbose=True):
try: try:
@ -178,6 +172,15 @@ class PrivCPU(CPU):
self.pc += self.INS_XLEN self.pc += self.INS_XLEN
except CpuTrap as trap: except CpuTrap as trap:
self._handle_trap(trap) self._handle_trap(trap)
if trap.interrupt == 0 and not isinstance(trap, EcallTrap):
print(FMT_CPU + "[CPU] Trap {} encountered at {} (0x{:x})".format(
trap,
self.mmu.translate_address(self.pc),
self.pc
) + FMT_NONE)
if self.conf.debug_on_exception:
raise LaunchDebuggerException()
self.pc += self.INS_XLEN
def _timer_step(self): def _timer_step(self):
if not self._time_interrupt_enabled: if not self._time_interrupt_enabled:
@ -193,7 +196,7 @@ class PrivCPU(CPU):
# TODO: actually select based on the official ranking # TODO: actually select based on the official ranking
trap = self.pending_traps.pop() # use the most recent trap trap = self.pending_traps.pop() # use the most recent trap
if not isinstance(trap, TimerInterrupt) or True: if not isinstance(trap, TimerInterrupt) or True:
print(FMT_CPU + "[CPU] [{}] taking trap {}!".format(self.cycle, trap) + FMT_NONE) print(FMT_CPU + "[CPU] taking trap {}!".format(trap) + FMT_NONE)
if trap.priv != PrivModes.MACHINE: if trap.priv != PrivModes.MACHINE:
print(FMT_CPU + "[CPU] Trap not targeting machine mode encountered! - undefined behaviour!" + FMT_NONE) print(FMT_CPU + "[CPU] Trap not targeting machine mode encountered! - undefined behaviour!" + FMT_NONE)
@ -206,7 +209,7 @@ class PrivCPU(CPU):
self.csr.set_mstatus('mpp', self.mode.value) self.csr.set_mstatus('mpp', self.mode.value)
self.csr.set_mstatus('mie', 0) self.csr.set_mstatus('mie', 0)
self.csr.set('mcause', trap.mcause) self.csr.set('mcause', trap.mcause)
self.csr.set('mepc', self.pc) self.csr.set('mepc', self.pc - self.INS_XLEN)
self.csr.set('mtval', trap.mtval) self.csr.set('mtval', trap.mtval)
self.mode = trap.priv self.mode = trap.priv
mtvec = self.csr.get('mtvec') mtvec = self.csr.get('mtvec')
@ -244,4 +247,3 @@ class PrivCPU(CPU):
def record_perf_profile(self): def record_perf_profile(self):
self._perf_counters.append((time.perf_counter_ns(), self.cycle)) self._perf_counters.append((time.perf_counter_ns(), self.cycle))

@ -22,6 +22,7 @@ class PrivMMU(MMU):
def translate_address(self, addr: int): def translate_address(self, addr: int):
return "" return ""
class LoadedElfMMU(PrivMMU): class LoadedElfMMU(PrivMMU):
def __init__(self, elf: ElfExecutable): def __init__(self, elf: ElfExecutable):
super().__init__(conf=RunConfig()) super().__init__(conf=RunConfig())

@ -79,15 +79,16 @@ class PrivRV32I(RV32I):
mepc = self.cpu.csr.get('mepc') mepc = self.cpu.csr.get('mepc')
self.cpu.pc = mepc - self.cpu.INS_XLEN self.cpu.pc = mepc - self.cpu.INS_XLEN
sec = self.mmu.get_sec_containing(mepc) if self.cpu.conf.verbosity > 0:
if sec is not None: sec = self.mmu.get_sec_containing(mepc)
print(FMT_CPU + "[CPU] [{}] returning to mode {} in {} (0x{:x})".format( if sec is not None:
self.cpu.cycle, print(FMT_CPU + "[CPU] returning to mode {} in {} (0x{:x})".format(
PrivModes(mpp).name, PrivModes(mpp).name,
self.mmu.translate_address(mepc), self.mmu.translate_address(mepc),
mepc mepc
) + FMT_NONE) ) + FMT_NONE)
self.regs.dump_reg_a() if self.cpu.conf.verbosity > 1:
self.regs.dump_reg_a()
def instruction_uret(self, ins: 'LoadedInstruction'): def instruction_uret(self, ins: 'LoadedInstruction'):
raise IllegalInstructionTrap(ins) raise IllegalInstructionTrap(ins)
@ -139,7 +140,7 @@ class PrivRV32I(RV32I):
ASSERT_LEN(ins.args, 2) ASSERT_LEN(ins.args, 2)
reg = ins.get_reg(0) reg = ins.get_reg(0)
addr = ins.get_imm(1) addr = ins.get_imm(1)
if reg == 'ra' and self.cpu.mode == PrivModes.USER: if reg == 'ra' and self.cpu.mode == PrivModes.USER and self.cpu.conf.verbosity > 1:
print(FMT_CPU + 'Jumping to {} (0x{:x})'.format( print(FMT_CPU + 'Jumping to {} (0x{:x})'.format(
self.mmu.translate_address(self.pc + addr), self.mmu.translate_address(self.pc + addr),
self.pc + addr self.pc + addr

@ -3,9 +3,6 @@ from .ImageLoader import MemoryImageMMU
from .PrivMMU import LoadedElfMMU from .PrivMMU import LoadedElfMMU
from .ElfLoader import ElfExecutable from .ElfLoader import ElfExecutable
from ..Tokenizer import RiscVInput
from ..ExecutableParser import ExecutableParser
import sys import sys
if __name__ == '__main__': if __name__ == '__main__':
@ -15,8 +12,9 @@ if __name__ == '__main__':
parser.add_argument('--kernel', type=str, help='Kernel elf loaded with user programs', nargs='?') parser.add_argument('--kernel', type=str, help='Kernel elf loaded with user programs', nargs='?')
parser.add_argument('--image', type=str, help='Memory image containing kernel', nargs='?') parser.add_argument('--image', type=str, help='Memory image containing kernel', nargs='?')
parser.add_argument('--debug-exceptions', help='Launch the interactive debugger when an exception is generated', action='store_true')
parser.add_argument('-v', '--verbose', help="Verbose output", action='store_true') parser.add_argument('-v', '--verbose', help="Verbosity level (can be used multiple times)", action='count', default=0)
args = parser.parse_args() args = parser.parse_args()
mmu = None mmu = None
@ -30,8 +28,8 @@ if __name__ == '__main__':
print("You must specify one of --kernel or --image for running in privilege mode!") print("You must specify one of --kernel or --image for running in privilege mode!")
sys.exit(1) sys.exit(1)
cpu = PrivCPU(RunConfig(), mmu) cpu = PrivCPU(RunConfig(verbosity=args.verbose, debug_on_exception=args.debug_exceptions), mmu)
cpu.run(args.verbose) cpu.run()

Loading…
Cancel
Save