overhaul of debugging info printing
This commit is contained in:
parent
d0c5abe845
commit
d09b7a5cb1
@ -1 +1 @@
|
||||
pyelftools~=0.27
|
||||
pyelftools~=0.27
|
||||
|
@ -19,4 +19,5 @@ class RunConfig:
|
||||
# allowed syscalls
|
||||
scall_input: bool = True
|
||||
scall_fs: bool = False
|
||||
verbosity: int = 0
|
||||
|
||||
|
@ -6,8 +6,6 @@ import time
|
||||
|
||||
|
||||
def _window_loop(textIO: 'TextIO'):
|
||||
#textIO.set_sg_window(None)
|
||||
#return
|
||||
try:
|
||||
import PySimpleGUI as sg
|
||||
|
||||
@ -30,10 +28,9 @@ def _window_loop(textIO: 'TextIO'):
|
||||
col.contents_changed()
|
||||
|
||||
except ImportError:
|
||||
print("[TextIO] module works best with PySimpleGui!")
|
||||
print("[TextIO] window disabled - please install PySimpleGui!")
|
||||
textIO.set_sg_window(None)
|
||||
|
||||
|
||||
class TextIO(IOModule):
|
||||
def __init__(self, addr: int, buflen: int = 128):
|
||||
super(TextIO, self).__init__(addr, buflen + 4)
|
||||
|
@ -6,7 +6,7 @@ SPDX-License-Identifier: MIT
|
||||
|
||||
from .Config import RunConfig
|
||||
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 .colors import *
|
||||
from typing import Dict, List, Tuple, Optional
|
||||
@ -109,7 +109,8 @@ class MMU:
|
||||
raise InvalidAllocationException('Invalid size request', name, req_size, flag)
|
||||
|
||||
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)
|
||||
size = align_addr(req_size)
|
||||
@ -203,6 +204,9 @@ class MMU:
|
||||
if symb in b.symbols:
|
||||
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):
|
||||
return "MMU(\n\t{}\n)".format(
|
||||
"\n\t".join(repr(x) for x in self.sections)
|
||||
|
@ -8,6 +8,7 @@ import typing
|
||||
from .Registers import Registers
|
||||
from .colors import FMT_DEBUG, FMT_NONE
|
||||
from .Executable import LoadedInstruction
|
||||
from .helpers import *
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from . import *
|
||||
@ -36,6 +37,9 @@ def launch_debug_session(cpu: 'CPU', mmu: 'MMU', reg: 'Registers', prompt=""):
|
||||
else:
|
||||
mmu.dump(what, *args, **kwargs)
|
||||
|
||||
def dump_stack(*args, **kwargs):
|
||||
mmu.dump(regs.get('sp'), *args, **kwargs)
|
||||
|
||||
def ins():
|
||||
print("Current instruction at 0x{:08X}:".format(cpu.pc))
|
||||
return mmu.read_ins(cpu.pc)
|
||||
|
@ -9,7 +9,7 @@ from .ElfLoader import ElfInstruction, ElfLoadedMemorySection, InstructionAccess
|
||||
from ..decoder import decode
|
||||
from ..IO.IOModule import IOModule
|
||||
from .privmodes import PrivModes
|
||||
from ..colors import FMT_ERROR, FMT_NONE
|
||||
from ..colors import FMT_ERROR, FMT_NONE, FMT_MEM
|
||||
import json
|
||||
|
||||
from functools import lru_cache
|
||||
@ -117,3 +117,10 @@ class MemoryImageMMU(PrivMMU):
|
||||
if addr >= val:
|
||||
return "{}{:+x} ({}:{})".format(sym, addr - val, sec.owner, sec.name)
|
||||
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):
|
||||
self.launch_debug = True
|
||||
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:
|
||||
print()
|
||||
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):
|
||||
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._run(verbose)
|
||||
self._run(self.conf.verbosity > 1)
|
||||
|
||||
def _init_csr(self):
|
||||
# set up CSR
|
||||
@ -162,8 +158,6 @@ class PrivCPU(CPU):
|
||||
def _handle_trap(self, trap: CpuTrap):
|
||||
# implement trap handling!
|
||||
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):
|
||||
try:
|
||||
@ -178,6 +172,15 @@ class PrivCPU(CPU):
|
||||
self.pc += self.INS_XLEN
|
||||
except CpuTrap as 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):
|
||||
if not self._time_interrupt_enabled:
|
||||
@ -193,7 +196,7 @@ class PrivCPU(CPU):
|
||||
# TODO: actually select based on the official ranking
|
||||
trap = self.pending_traps.pop() # use the most recent trap
|
||||
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:
|
||||
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('mie', 0)
|
||||
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.mode = trap.priv
|
||||
mtvec = self.csr.get('mtvec')
|
||||
@ -244,4 +247,3 @@ class PrivCPU(CPU):
|
||||
|
||||
def record_perf_profile(self):
|
||||
self._perf_counters.append((time.perf_counter_ns(), self.cycle))
|
||||
|
||||
|
@ -22,6 +22,7 @@ class PrivMMU(MMU):
|
||||
def translate_address(self, addr: int):
|
||||
return ""
|
||||
|
||||
|
||||
class LoadedElfMMU(PrivMMU):
|
||||
def __init__(self, elf: ElfExecutable):
|
||||
super().__init__(conf=RunConfig())
|
||||
|
@ -79,15 +79,16 @@ class PrivRV32I(RV32I):
|
||||
mepc = self.cpu.csr.get('mepc')
|
||||
self.cpu.pc = mepc - self.cpu.INS_XLEN
|
||||
|
||||
sec = self.mmu.get_sec_containing(mepc)
|
||||
if sec is not None:
|
||||
print(FMT_CPU + "[CPU] [{}] returning to mode {} in {} (0x{:x})".format(
|
||||
self.cpu.cycle,
|
||||
PrivModes(mpp).name,
|
||||
self.mmu.translate_address(mepc),
|
||||
mepc
|
||||
) + FMT_NONE)
|
||||
self.regs.dump_reg_a()
|
||||
if self.cpu.conf.verbosity > 0:
|
||||
sec = self.mmu.get_sec_containing(mepc)
|
||||
if sec is not None:
|
||||
print(FMT_CPU + "[CPU] returning to mode {} in {} (0x{:x})".format(
|
||||
PrivModes(mpp).name,
|
||||
self.mmu.translate_address(mepc),
|
||||
mepc
|
||||
) + FMT_NONE)
|
||||
if self.cpu.conf.verbosity > 1:
|
||||
self.regs.dump_reg_a()
|
||||
|
||||
def instruction_uret(self, ins: 'LoadedInstruction'):
|
||||
raise IllegalInstructionTrap(ins)
|
||||
@ -139,7 +140,7 @@ class PrivRV32I(RV32I):
|
||||
ASSERT_LEN(ins.args, 2)
|
||||
reg = ins.get_reg(0)
|
||||
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(
|
||||
self.mmu.translate_address(self.pc + addr),
|
||||
self.pc + addr
|
||||
|
@ -3,9 +3,6 @@ from .ImageLoader import MemoryImageMMU
|
||||
from .PrivMMU import LoadedElfMMU
|
||||
from .ElfLoader import ElfExecutable
|
||||
|
||||
from ..Tokenizer import RiscVInput
|
||||
from ..ExecutableParser import ExecutableParser
|
||||
|
||||
import sys
|
||||
|
||||
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('--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()
|
||||
mmu = None
|
||||
@ -30,8 +28,8 @@ if __name__ == '__main__':
|
||||
print("You must specify one of --kernel or --image for running in privilege mode!")
|
||||
sys.exit(1)
|
||||
|
||||
cpu = PrivCPU(RunConfig(), mmu)
|
||||
cpu.run(args.verbose)
|
||||
cpu = PrivCPU(RunConfig(verbosity=args.verbose, debug_on_exception=args.debug_exceptions), mmu)
|
||||
cpu.run()
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user