Merge branch 'master' into npc
Some checks failed
Build abstract machine with nix / build-abstract-machine (push) Has been cancelled

This commit is contained in:
xin 2024-03-26 03:12:30 +00:00
commit 642444b384
44 changed files with 924 additions and 110 deletions

View file

@ -0,0 +1,21 @@
name: Build abstract machine with nix
on: [push]
jobs:
build-abstract-machine:
runs-on: nix
steps:
- uses: https://github.com/cachix/cachix-action@v14
with:
name: ysyx
signingKey: '${{ secrets.CACHIX_SIGNING_KEY }}'
- uses: actions/checkout@v4
with:
submodules: true
- name: Build abstract-machine
run: |
nix build .#abstract-machine
- name: Build nemu
run: |
nix build .#nemu

3
.gitignore vendored
View file

@ -10,4 +10,5 @@
!init.sh
/fceux-am
/nvboard
/am-kernels
**/.cache
**/result

3
.gitmodules vendored Normal file
View file

@ -0,0 +1,3 @@
[submodule "am-kernels"]
path = am-kernels
url = https://git.xinyang.life/xin/am-kernels.git

View file

@ -1,19 +1,6 @@
*
!*/
!*.h
!*.c
!*.cc
!*.S
!*.ld
!*.sh
!*.py
!*.mk
!Makefile
!README
!LICENSE
.*
_*
*~
build/
!.gitignore
.vscode
**/.direnv/
**/build/
**/.envrc
**/.cache
.vscode
compile_commands.json

View file

@ -0,0 +1,87 @@
cmake_minimum_required(VERSION 3.22)
project(abstract-machine)
enable_language(CXX C ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 11)
include(CMakeDependentOption)
include(CMakePackageConfigHelpers) # Used to find libcheck
include(CTest)
# -- General options
set(ISA CACHE STRING "Target ISA")
set_property(CACHE ISA PROPERTY STRINGS "riscv" "x86" "x86_64" "native")
string(TOUPPER ${ISA} ISA_UPPER)
cmake_dependent_option(
__PLATFORM_NEMU__ "Run on NEMU"
ON "ISA MATCHES \"(riscv | x86)\"" OFF)
cmake_dependent_option(
__PLATFORM_NATIVE__ "Run on native"
ON "ISA MATCHES native" OFF)
# -- Set PLATFORM according to options
set(MATCH_PLATFORM_PATTERN "^__PLATFORM_([A-Z]*)__")
get_cmake_property(CACHE_VARS CACHE_VARIABLES)
message(STATUS "ISA: ${ISA}")
foreach(VAR IN LISTS CACHE_VARS)
if(VAR MATCHES ${MATCH_PLATFORM_PATTERN})
# Retrieve the value of the cache variable
get_property(VAR_VALUE CACHE ${VAR} PROPERTY VALUE)
set(PLATFORM_UPPER ${CMAKE_MATCH_1})
string(TOLOWER ${PLATFORM_UPPER} PLATFORM)
message(STATUS "Variable: ${VAR}=${VAR_VALUE}, Platform: ${PLATFORM}")
endif()
endforeach()
if(${PLATFORM} MATCHES "native")
set(ARCH "native")
else()
set(ARCH ${ISA}-${PLATFORM})
endif()
string(TOUPPER ${ARCH} ARCH_UPPER)
# -- Target specific options
cmake_dependent_option(
NATIVE_USE_KLIB "Use Klib even if on native"
ON "NOT __ISA_NATIVE__" OFF)
# -- Add compile definitions based on options
add_compile_definitions(
$<MAKE_C_IDENTIFIER:__ARCH_${ARCH_UPPER}__>
__ISA_${ISA_UPPER}__
__PLATFORM_${PLATFORM_UPPER}__
)
add_compile_definitions(
$<$<BOOL:${NATIVE_USE_KLIB}>:__NATIVE_USE_KLIB__>
)
# -- Required compiler flags
add_compile_options(
# -Werror
-Wno-main
-fno-asynchronous-unwind-tables
-fno-builtin
-fno-stack-protector
-U_FORTIFY_SOURCE
$<$<COMPILE_LANGUAGE:CXX>:-fno-exceptions>
$<$<COMPILE_LANGUAGE:CXX>:-ffreestanding>
$<$<COMPILE_LANGUAGE:CXX>:-fno-rtti>)
add_link_options(
-znoexecstack
)
# -- Include linker script here. Use this linker script at link time if INCLUDE_LINKER_SCRIPT is set to true
set(LINKER_SCRIPT linker.ld)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
add_compile_options(-march=rv32if -mabi=ilp32)
add_link_options(-march=rv32if -mabi=ilp32)
add_subdirectory(klib)
add_subdirectory(am)

View file

@ -0,0 +1,29 @@
{
"version": 6,
"configurePresets": [
{
"name": "native",
"displayName": "Native",
"generator": "Unix Makefiles",
"binaryDir": "${sourceDir}/out/build/${presetName}",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"ISA": "native",
"__PLATFORM_NATIVE__": true,
"NATIVE_USE_KLIB": true
}
},
{
"name": "riscv-nemu",
"displayName": "Riscv32 NEMU",
"generator": "Unix Makefiles",
"binaryDir": "${sourceDir}/out/build/${presetName}",
"installDir": "/home/xin/repo/ysyx-workbench/abstract-machine/out/install",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"ISA": "riscv",
"__PLATFORM_NEMU__": true
}
}
]
}

View file

@ -0,0 +1,10 @@
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
add_library(am_interface INTERFACE)
target_include_directories(am_interface INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include/abstract-machine>)
add_subdirectory(src)
install(DIRECTORY include/ DESTINATION include/abstract-machine)

View file

@ -0,0 +1,53 @@
if(ISA MATCHES "native")
set(SOURCEDIR "./${PLATFORM}")
else()
set(SOURCEDIR "./${ISA}/${PLATFORM}")
endif()
add_subdirectory(${SOURCEDIR})
target_include_directories(am-${ARCH}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../include>
$<INSTALL_INTERFACE:include/abstract-machine>)
target_link_libraries(am-${ARCH}
PUBLIC klib_interface
INTERFACE m)
# TODO: Check
target_link_options(am-${ARCH} INTERFACE
$<BUILD_INTERFACE:-T${CMAKE_SOURCE_DIR}/scripts/${LINKER_SCRIPT}>
$<INSTALL_INTERFACE:-T${CMAKE_INSTALL_LIBDIR}/cmake/am-${ARCH}/${LINKER_SCRIPT}>)
# Interface compile flags
target_link_options(am-${ARCH} INTERFACE
-znoexecstack)
target_compile_options(am-${ARCH} INTERFACE
-fno-asynchronous-unwind-tables
-fno-builtin
-fno-stack-protector
-U_FORTIFY_SOURCE
$<$<COMPILE_LANGUAGE:CXX>:-fno-exceptions>
$<$<COMPILE_LANGUAGE:CXX>:-ffreestanding>
$<$<COMPILE_LANGUAGE:CXX>:-fno-rtti>)
install(TARGETS am-${ARCH} klib_interface am_interface
EXPORT amTargets
LIBRARY DESTINATION lib)
install(EXPORT amTargets
FILE amTargets.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/am-${ARCH})
configure_package_config_file(${CMAKE_SOURCE_DIR}/cmake/am-config.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/am-${ARCH}-config.cmake
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/am-${ARCH})
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/am-${ARCH}-config.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/am-${ARCH})
# TODO: check
install(FILES ${CMAKE_SOURCE_DIR}/scripts/${LINKER_SCRIPT}
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/am-${ARCH})

View file

@ -0,0 +1,26 @@
include(CheckPIESupported)
check_pie_supported()
set(SOURCES
trap.S
cte.c
ioe.c
mpe.c
platform.c
trm.c
vme.c
ioe/audio.c
ioe/disk.c
ioe/gpu.c
ioe/input.c
ioe/timer.c
)
add_library(am-native ${SOURCES})
# FIXME: get free(): invalid address when user program compiled without pie
set_target_properties(am-native PROPERTIES
POSITION_INDEPENDENT_CODE TRUE
INTERFACE_POSITION_INDEPENDENT_CODE TRUE)
find_package(SDL2 REQUIRED)
target_link_libraries(am-${ARCH} PUBLIC SDL2::SDL2)

View file

@ -0,0 +1,34 @@
include(nemu-settings)
include(riscv-settings)
add_library(am-${ISA}-nemu
cte.c
start.S
trap.S
vme.c
${NEMU_SOURCES}
)
target_compile_options(am-${ISA}-nemu PRIVATE
${NEMU_COMPILE_OPTIONS}
${RISCV_COMPILE_OPTIONS})
target_link_options(am-${ISA}-nemu PRIVATE
${NEMU_LINK_OPITIONS}
${RISCV_LINK_OPTIONS})
target_include_directories(am-${ISA}-nemu PRIVATE
${NEMU_INCLUDE_DIRECTORIES})
target_link_options(am-${ISA}-nemu INTERFACE
LINKER:--defsym=_pmem_start=0x80000000
LINKER:--defsym=_entry_offset=0x0
LINKER:--gc-sections
LINKER:-e _start
-nostartfiles)
target_compile_definitions(am-${ISA}-nemu PUBLIC
ARCH_H="arch/riscv.h")
target_compile_definitions(am-${ISA}-nemu PRIVATE
ISA_H="riscv/riscv.h")
set_target_properties(am-${ISA}-nemu PROPERTIES
POSITION_INDEPENDENT_CODE OFF
INTERFACE_POSITION_INDEPENDENT_CODE OFF)

View file

@ -0,0 +1,9 @@
@PACKAGE_INIT@
include(CMakeFindDependencyMacro)
if(${ARCH} MATCHES "native")
find_dependency(SDL2 REQUIRED)
endif()
# Include the targets file
include("${CMAKE_CURRENT_LIST_DIR}/amTargets.cmake")

View file

@ -0,0 +1,6 @@
@PACKAGE_INIT@
include(CMakeFindDependencyMacro)
# Include the targets file
include("${CMAKE_CURRENT_LIST_DIR}/klibTargets.cmake")

View file

@ -0,0 +1,11 @@
set(NEMU_COMPILE_OPTIONS -fdata-sections -ffunction-sections)
set(NEMU_LINK_OPTIONS
--defsym=_pmem_start=0x80000000
--defsym=_entry_offset=0x0
--gc-sections
-e _start)
set(NEMU_INCLUDE_DIRECTORIES
${CMAKE_SOURCE_DIR}/am/src/platform/nemu/include)
file(GLOB_RECURSE NEMU_SOURCES
${CMAKE_SOURCE_DIR}/am/src/platform/nemu/*.[cS])
set(INCLUDE_LINKER_SCRIPT ON)

View file

@ -0,0 +1,2 @@
set(RISCV_COMPILE_OPTIONS)
set(RISCV_LINK_OPTIONS)

View file

@ -0,0 +1,26 @@
{ stdenv,
lib,
cmake,
SDL2,
isa ? "native",
platform ? "NEMU"
}:
stdenv.mkDerivation {
pname = "abstract-machine";
version = "2024.02.18";
src = ./.;
cmakeFlags = [
(lib.cmakeFeature "ISA" isa)
(lib.cmakeBool "__PLATFORM_${lib.strings.toUpper platform}__" true)
];
nativeBuildInputs = [
cmake
];
buildInputs = [
] ++ (if platform=="native" then [ SDL2 ] else [ ]);
}

View file

@ -0,0 +1,12 @@
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
add_library(klib_interface INTERFACE)
target_include_directories(klib_interface
INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include/abstract-machine>)
add_subdirectory(src)
# add_subdirectory(tests)
install(DIRECTORY include/ DESTINATION include/abstract-machine)

View file

@ -35,6 +35,7 @@ int atoi (const char *nptr);
int printf (const char *format, ...);
int sprintf (char *str, const char *format, ...);
int snprintf (char *str, size_t size, const char *format, ...);
int vprintf (const char *format, va_list ap);
int vsprintf (char *str, const char *format, va_list ap);
int vsnprintf (char *str, size_t size, const char *format, va_list ap);

View file

@ -0,0 +1,33 @@
# find_package(FLEX)
# find_package(BISON)
# FLEX_TARGET(fmt_scanner fmt_scanner.l fmt_scanner.c)
set(SOURCES
cpp.c
int64.c
stdio.c
stdlib.c
string.c
# ${FLEX_fmt_scanner_OUTPUTS}
)
add_library(klib ${SOURCES})
target_include_directories(klib PUBLIC $<TARGET_PROPERTY:am_interface,INTERFACE_INCLUDE_DIRECTORIES>)
target_compile_definitions(klib PUBLIC $<TARGET_PROPERTY:am-${ARCH},INTERFACE_COMPILE_DEFINITIONS>)
install(TARGETS klib
EXPORT klibTargets
LIBRARY DESTINATION lib)
install(EXPORT klibTargets
FILE klibTargets.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/klib)
configure_package_config_file(${CMAKE_SOURCE_DIR}/cmake/klib-config.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/klib-config.cmake
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/klib)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/klib-config.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/klib)

View file

@ -5,8 +5,20 @@
#if !defined(__ISA_NATIVE__) || defined(__NATIVE_USE_KLIB__)
int vprintf(const char *fmt, va_list ap) {
const char *p = fmt;
while(*p != '\0') {
putch(*p);
}
return 0;
}
int printf(const char *fmt, ...) {
panic("Not implemented");
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
return 0;
}
int vsprintf(char *out, const char *fmt, va_list ap) {

View file

@ -5,43 +5,115 @@
#if !defined(__ISA_NATIVE__) || defined(__NATIVE_USE_KLIB__)
size_t strlen(const char *s) {
panic("Not implemented");
const char *p = s;
size_t len = 0;
while(*(p++) != '\0') len++;
return len;
}
char *strcpy(char *dst, const char *src) {
panic("Not implemented");
char *p_dst = dst;
const char *p_src = src;
for(; *p_src != '\0'; p_src++, p_dst++) {
*p_dst = *p_src;
}
*p_dst = '\0';
return dst;
}
char *strncpy(char *dst, const char *src, size_t n) {
panic("Not implemented");
int i = 0;
for(; i < n && src[i] != '\0'; i++) {
dst[i] = src[i];
}
for(; i < n; i++) {
dst[i] = '\0';
}
return dst;
}
char *strcat(char *dst, const char *src) {
panic("Not implemented");
char *p_dst = dst;
const char *p_src = src;
while(*p_dst != '\0') p_dst++;
for(; *p_src != '\0'; p_src++, p_dst++) {
*p_dst = *p_src;
}
*p_dst = '\0';
return dst;
}
int strcmp(const char *s1, const char *s2) {
panic("Not implemented");
const char *p_s1 = s1, *p_s2 = s2;
for(; *p_s1 == *p_s2; p_s1++, p_s2++) {
if(*p_s1 == '\0' || *p_s2 == '\0') {
break;
}
}
return *p_s1 - *p_s2;
}
int strncmp(const char *s1, const char *s2, size_t n) {
panic("Not implemented");
const char *p_s1 = s1, *p_s2 = s2;
int i = 0;
for(i = 0; i < n - 1; i++) {
if(s1[i] == '\0' || s2[i] == '\0')
break;
}
return s1[i] - s2[i];
}
void *memset(void *s, int c, size_t n) {
panic("Not implemented");
uint8_t *p = s;
for(int i = 0; i < n; i++) {
p[i] = c;
}
return s;
}
void *memmove(void *dst, const void *src, size_t n) {
panic("Not implemented");
if (src + n > dst && src < dst) {
size_t len = dst - src;
void *p_dst = (void *)src + n;
const void *p_src = src + n - len;
while(p_dst >= dst) {
memcpy(p_dst, p_src, len);
p_src -= len;
p_dst -= len;
}
if(n % len) memcpy(dst, src, n % len);
} else if (dst < src && dst + n > src) {
size_t len = src - dst;
void *p_dst = dst;
const void *p_src = src;
while(p_src < src + n) {
memcpy(p_dst, p_src, len);
p_src += len;
p_dst += len;
}
if(n % len) memcpy(p_dst, p_src, n % len);
} else {
memcpy(dst, src, n);
}
return dst;
}
void *memcpy(void *out, const void *in, size_t n) {
panic("Not implemented");
for (size_t i = 0 ; i < n ; i++) {
*(uint8_t *)(out + i) = *(uint8_t *)(in + i);
}
return out;
}
int memcmp(const void *s1, const void *s2, size_t n) {
panic("Not implemented");
const uint8_t *p1 = s1, *p2 = s2;
for (int i = 0; i < n; i++) {
if(*p1 != *p2)
return p1 - p2;
p1++; p2++;
}
return 0;
}
#endif

View file

@ -0,0 +1,17 @@
set(TEST_SOURCES
stdio
string
)
foreach(TEST IN LISTS TEST_SOURCES)
add_executable(${TEST} ${TEST}.c)
target_link_libraries(${TEST} am-${ARCH} klib m)
target_include_directories(${TEST}
PRIVATE $<TARGET_PROPERTY:am_interface,INTERFACE_INCLUDE_DIRECTORIES>
PRIVATE $<TARGET_PROPERTY:klib_interface,INTERFACE_INCLUDE_DIRECTORIES>
)
# TODO: Run tests in other configurations
if(__PLATFORM_NATIVE__)
add_test(NAME ${TEST} COMMAND ${TEST})
endif()
endforeach()

View file

@ -0,0 +1,5 @@
#include <klib.h>
int main(void) {
return 0;
}

View file

@ -0,0 +1,75 @@
#include <klib.h>
#include <klib-macros.h>
#include <stdint.h>
void test_strcpy() {
char b[32];
char *s;
b[16]='a'; b[17]='b'; b[18]='c'; b[19]=0;
panic_on((s = strcpy(b, b+16)) != b, "strcpy wrong return value");
panic_on(strcmp(s, "abc") != 0, "strcpy gave incorrect string");
panic_on((s = strcpy(b+1, b+16)) != b+1, "strcpy wrong return value");
panic_on(strcmp(s, "abc") != 0, "strcpy gave incorrect string");
panic_on((s = strcpy(b+1, b+17)) != b+1, "strcpy wrong return value");
panic_on(strcmp(s, "bc") != 0, "strcpy gave incorrect string");
}
void test_strncpy() {
char b[32];
char *s;
int i;
b[3] = 'x'; b[4] = 0;
panic_on((s = strncpy(b, "abc", 3)) != b, "strncpy wrong return value");
panic_on(b[2] != 'c', "strncpy fails to copy last byte");
panic_on(b[3] != 'x', "strncpy overruns buffer to null-terminate");
}
void test_strncmp() {
panic_on(strncmp("abcd", "abce", 3) != 0, "strncmp compares past n");
panic_on(strncmp("abc", "abd", 3) == 0, "strncmp fails to compare n-1st byte");
}
void test_memset() {
uint8_t arr[128];
arr[120] = 0xd;
panic_on(memset(arr, 0xf, 120) != arr, "memset wrong return value");
panic_on(arr[7] != 0xf, "memset fails to set value in range");
panic_on(arr[120] != 0xd, "memset set value past n");
}
void test_memcpy() {
const uint8_t src[] = { 0x0, 0x0, 0x1, 0x2, 0x3, 0x4, 0x0, 0x0 };
uint8_t dst[8] = {0};
memcpy(dst, src, 8);
panic_on(memcmp(dst, src, 8) != 0, "memcpy fails to copy memory");
}
void test_memmove() {
const uint8_t ref[] = { 0x0, 0x0, 0x1, 0x2, 0x3, 0x4, 0x0, 0x0 };
uint8_t dst[8] = {0};
const uint8_t ans1[] = { 0x1, 0x2, 0x3, 0x4, 0x3, 0x4, 0x0, 0x0 };
const uint8_t ans2[] = { 0x1, 0x2, 0x2, 0x3, 0x4, 0x3, 0x0, 0x0 };
const uint8_t ans3[] = { 0x1, 0x2, 0x2, 0x1, 0x2, 0x2, 0x3, 0x4 };
memmove(dst, ref, 8);
panic_on(memcmp(dst, ref, 8) != 0, "memmove fails to copy non-overlapping memory");
memmove(dst, dst + 2, 4);
panic_on(memcmp(dst, ans1, 8) != 0, "memmove fails to copy overlapping memory (dst < src)");
memmove(dst + 2, dst + 1, 4);
panic_on(memcmp(dst, ans2, 8) != 0, "memmove fails to copy overlapping memory (src < dst)");
memmove(dst + 3, dst, 5);
panic_on(memcmp(dst, ans3, 8) != 0, "memmove fails to copy overlapping memory (src < dst)");
}
int main(void) {
test_strcpy();
test_strncpy();
test_strncmp();
test_memset();
test_memcpy();
test_memmove();
return 0;
}

Binary file not shown.

1
am-kernels Submodule

@ -0,0 +1 @@
Subproject commit 2f559823a63cf6909d5a9e32dee47d6891caf553

View file

@ -12,59 +12,43 @@
localSystem = system;
crossSystem = {
config = "riscv32-none-elf";
abi = "ilp32";
gcc = {
abi = "ilp32";
arch = "rv32if";
};
};
};
in
{
packages.nemu = pkgs.callPackage ./nemu { am-kernels = self.packages.${system}.am-kernels; };
packages.abstract-machine = crossPkgs.callPackage ./abstract-machine { isa = "riscv"; platform = "nemu"; };
packages.am-kernels = crossPkgs.stdenv.mkDerivation rec {
pname = "am-kernels";
pname = "am-kernels-cmake";
version = "2024.02.18";
src = pkgs.fetchFromGitHub {
owner = "NJU-ProjectN";
repo = "am-kernels";
rev = "bb725d6f8223dd7de831c3b692e8c4531e9d01af";
hash = "sha256-ZHdrw28TN8cMvhhzM469OV7cp0Yp+8yao855HP4+P4A=";
};
src = ./am-kernels;
AM_HOME = pkgs.fetchFromGitHub {
owner = "xinyangli";
repo = "abstract-machine";
rev = "788595aac61c6b2f3b78ca8aa7d08dc33911bca4";
hash = "sha256-YvWHIBP9tz3HL2TyibftvvQrpkWUDPnviCF4oyLmdjg=";
};
nativeBuildInputs = [
pkgs.cmake
];
ARCH = "riscv32-nemu";
cmakeFlags = [
(pkgs.lib.cmakeFeature "ISA" "riscv")
(pkgs.lib.cmakeFeature "PLATFORM" "nemu")
(pkgs.lib.cmakeFeature "CMAKE_INSTALL_DATADIR" "share")
];
patchPhase = ''
sed -i 's/\/bin\/echo/echo/' tests/cpu-tests/Makefile
'';
buildPhase = ''
AS=$CC make -C tests/cpu-tests BUILD_DIR=$(pwd)/build ARCH=$ARCH
'';
installPhase = ''
mkdir -p $out/share/images $out/share/dump
cp build/riscv32-nemu/*.bin $out/share/images
cp build/riscv32-nemu/*.txt $out/share/dump
'';
dontFixup = true;
};
devShells.default = pkgs.mkShell {
packages = with pkgs; [
gdb
] ++ builtins.attrValues self.packages.${system};
buildInputs = [
# SDL2
self.packages.${system}.abstract-machine
];
};
devShells.nemu = pkgs.mkShell {
packages = with pkgs; [
clang-tools
gdb
];
inputsFrom = [
self.packages.${system}.nemu
@ -73,4 +57,3 @@
}
);
}

View file

@ -143,14 +143,54 @@ config TRACE_END
config ITRACE
depends on TRACE && TARGET_NATIVE_ELF && ENGINE_INTERPRETER
bool "Enable instruction tracer"
bool "Enable instruction tracing"
default y
help
Instraction tracing will log past instructions into a ring buffer
and print them when NEMU exit unexpectedly.
config ITRACE_COND
depends on ITRACE
string "Only trace instructions when the condition is true"
default "true"
config ITRACE_BUFFER
depends on ITRACE
int "Buffer size for intruction trace (unit: number of instructions)"
default 10
config MTRACE
depends on TRACE && TARGET_NATIVE_ELF && ENGINE_INTERPRETER
bool "Enable memory tracing"
default n
config MTRACE_RANGE
depends on MTRACE
string "Memory trace active range"
default "0x0-0xfffffff"
help
Memory tracer will only print memory access in these ranges.
Use comma to seperate between ranges.
config MTRACE_RANGE_MAX
depends on MTRACE
int "Max range count in MTRACE_RANGE"
default 10
config FTRACE
depends on TRACE && TARGET_NATIVE_ELF && ENGINE_INTERPRETER
bool "Enable function tracing"
default y
config FTRACE_STACK_SIZE
depends on FTRACE
int "Max function track stack size"
default 100
config FTRACE_LOG
depends on FTRACE
bool "Print log when entering a funciton"
default n
config DIFFTEST
depends on TARGET_NATIVE_ELF

View file

@ -94,4 +94,4 @@ integration-tests: $(IMAGES)
test: unit-tests integration-tests
.PHONY: test unit-tests integration-tests
.PHONY: test unit-tests integration-tests

View file

@ -1,7 +1,8 @@
{ pkgs,
lib,
stdenv,
am-kernels
am-kernels,
dtc
}:
stdenv.mkDerivation rec {
@ -15,6 +16,7 @@ stdenv.mkDerivation rec {
pkg-config
flex
bison
dtc
];
buildInputs = with pkgs; [
@ -38,7 +40,7 @@ stdenv.mkDerivation rec {
doCheck = true;
checkPhase = ''
export IMAGES_PATH=${am-kernels}/share/images
export IMAGES_PATH=${am-kernels}/share/binary
make test
'';
@ -49,7 +51,7 @@ stdenv.mkDerivation rec {
shellHook = ''
export NEMU_HOME=$(pwd)
export IMAGES_PATH=${am-kernels}/share/images
export IMAGES_PATH=${am-kernels}/share/binary
'';
meta = with lib; {

View file

@ -17,12 +17,12 @@
#define __COMMON_H__
#include <stdint.h>
#include <inttypes.h>
#include <stdbool.h>
#include <string.h>
#include <generated/autoconf.h>
#include <macro.h>
#include <types.h>
#ifdef CONFIG_TARGET_AM
#include <klib.h>
@ -31,23 +31,6 @@
#include <stdlib.h>
#endif
#if CONFIG_MBASE + CONFIG_MSIZE > 0x100000000ul
#define PMEM64 1
#endif
typedef MUXDEF(CONFIG_ISA64, uint64_t, uint32_t) word_t;
typedef MUXDEF(CONFIG_ISA64, int64_t, int32_t) sword_t;
static const word_t WORD_T_MAX = MUXDEF(CONFIG_ISA64, UINT64_MAX, UINT32_MAX);
static const sword_t SWORD_T_MAX = MUXDEF(CONFIG_ISA64, INT64_MAX, INT32_MAX);
static const sword_t SWORD_T_MIN = MUXDEF(CONFIG_ISA64, INT64_MIN, INT32_MIN);
#define WORD_BYTES MUXDEF(CONFIG_ISA64, 8, 4)
#define FMT_WORD MUXDEF(CONFIG_ISA64, "0x%016" PRIx64, "0x%08" PRIx32)
typedef word_t vaddr_t;
typedef MUXDEF(PMEM64, uint64_t, uint32_t) paddr_t;
#define FMT_PADDR MUXDEF(PMEM64, "0x%016" PRIx64, "0x%08" PRIx32)
typedef uint16_t ioaddr_t;
#include <debug.h>
#endif

View file

@ -23,7 +23,6 @@ typedef struct Decode {
vaddr_t snpc; // static next pc
vaddr_t dnpc; // dynamic next pc
ISADecodeInfo isa;
IFDEF(CONFIG_ITRACE, char logbuf[128]);
} Decode;
// --- pattern matching mechanism ---

View file

@ -16,9 +16,14 @@
#ifndef __DEBUG_H__
#define __DEBUG_H__
#include <common.h>
#include <stdio.h>
#include <utils.h>
#include <macro.h>
IFDEF(CONFIG_ITRACE, void log_itrace_print());
#define Trace(format, ...) \
_Log("[TRACE] " format "\n", ## __VA_ARGS__)
#define Log(format, ...) \
_Log(ANSI_FMT("[INFO] %s:%d %s() ", ANSI_FG_BLUE) format "\n", \
@ -38,6 +43,7 @@
MUXDEF(CONFIG_TARGET_AM, printf(ANSI_FMT(format, ANSI_FG_RED) "\n", ## __VA_ARGS__), \
(fflush(stdout), fprintf(stderr, ANSI_FMT(format, ANSI_FG_RED) "\n", ## __VA_ARGS__))); \
IFNDEF(CONFIG_TARGET_AM, extern FILE* log_fp; fflush(log_fp)); \
IFDEF(CONFIG_ITRACE, log_itrace_print()); \
extern void assert_fail_msg(); \
assert_fail_msg(); \
assert(cond); \

18
nemu/include/ftrace.h Normal file
View file

@ -0,0 +1,18 @@
#ifndef __FUNC_DEF_H__
#define __FUNC_DEF_H__
#include <common.h>
#ifdef CONFIG_FTRACE
typedef struct {
vaddr_t start;
vaddr_t len;
char * name;
} func_t;
extern func_t *func_table;
void ftrace_call(vaddr_t, vaddr_t);
void ftrace_return(vaddr_t, vaddr_t);
// const char *get_func_name(vaddr_t addr);
#endif
#endif

View file

@ -92,6 +92,8 @@
#define PG_ALIGN __attribute((aligned(4096)))
#define FAILED_GOTO(tag, exp) do {if((exp)) goto tag;} while(0)
#if !defined(likely)
#define likely(cond) __builtin_expect(cond, 1)
#define unlikely(cond) __builtin_expect(cond, 0)

21
nemu/include/types.h Normal file
View file

@ -0,0 +1,21 @@
#ifndef __TYPES_H__
#define __TYPES_H__
#include <inttypes.h>
#include <macro.h>
#if CONFIG_MBASE + CONFIG_MSIZE > 0x100000000ul
#define PMEM64 1
#endif
typedef MUXDEF(CONFIG_ISA64, uint64_t, uint32_t) word_t;
typedef MUXDEF(CONFIG_ISA64, int64_t, int32_t) sword_t;
static const word_t WORD_T_MAX = MUXDEF(CONFIG_ISA64, UINT64_MAX, UINT32_MAX);
static const sword_t SWORD_T_MAX = MUXDEF(CONFIG_ISA64, INT64_MAX, INT32_MAX);
static const sword_t SWORD_T_MIN = MUXDEF(CONFIG_ISA64, INT64_MIN, INT32_MIN);
#define WORD_BYTES MUXDEF(CONFIG_ISA64, 8, 4)
#define FMT_WORD MUXDEF(CONFIG_ISA64, "0x%016" PRIx64, "0x%08" PRIx32)
typedef word_t vaddr_t;
typedef MUXDEF(PMEM64, uint64_t, uint32_t) paddr_t;
#define FMT_PADDR MUXDEF(PMEM64, "0x%016" PRIx64, "0x%08" PRIx32)
typedef uint16_t ioaddr_t;
#endif

View file

@ -16,7 +16,7 @@
#ifndef __UTILS_H__
#define __UTILS_H__
#include <common.h>
#include <types.h>
// ----------- state -----------

View file

@ -13,6 +13,7 @@
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include <utils.h>
#include <cpu/cpu.h>
#include <cpu/decode.h>
#include <cpu/difftest.h>
@ -29,15 +30,17 @@ CPU_state cpu = {};
uint64_t g_nr_guest_inst = 0;
static uint64_t g_timer = 0; // unit: us
static bool g_print_step = false;
IFDEF(CONFIG_ITRACE, extern char logbuf[CONFIG_ITRACE_BUFFER][128]);
IFDEF(CONFIG_ITRACE, extern int logbuf_rear);
void device_update();
bool wp_eval_all();
static void trace_and_difftest(Decode *_this, vaddr_t dnpc) {
#ifdef CONFIG_ITRACE_COND
if (ITRACE_COND) { log_write("%s\n", _this->logbuf); }
if (ITRACE_COND) { log_write("%s\n", logbuf[logbuf_rear]); }
#endif
if (g_print_step) { IFDEF(CONFIG_ITRACE, puts(_this->logbuf)); }
if (g_print_step) { IFDEF(CONFIG_ITRACE, puts(logbuf[logbuf_rear])); }
IFDEF(CONFIG_DIFFTEST, difftest_step(_this->pc, dnpc));
}
@ -47,8 +50,9 @@ static void exec_once(Decode *s, vaddr_t pc) {
isa_exec_once(s);
cpu.pc = s->dnpc;
#ifdef CONFIG_ITRACE
char *p = s->logbuf;
p += snprintf(p, sizeof(s->logbuf), FMT_WORD ":", s->pc);
logbuf_rear = (logbuf_rear + 1) % CONFIG_ITRACE_BUFFER;
char *p = logbuf[logbuf_rear];
p += snprintf(p, sizeof(logbuf), FMT_WORD ":", s->pc);
int ilen = s->snpc - s->pc;
int i;
uint8_t *inst = (uint8_t *)&s->isa.inst.val;
@ -64,7 +68,7 @@ static void exec_once(Decode *s, vaddr_t pc) {
#ifndef CONFIG_ISA_loongarch32r
void disassemble(char *str, int size, uint64_t pc, uint8_t *code, int nbyte);
disassemble(p, s->logbuf + sizeof(s->logbuf) - p,
disassemble(p, logbuf[logbuf_rear] + sizeof(logbuf[logbuf_rear]) - p,
MUXDEF(CONFIG_ISA_x86, s->snpc, s->pc), (uint8_t *)&s->isa.inst.val, ilen);
#else
p[0] = '\0'; // the upstream llvm does not support loongarch32r
@ -79,7 +83,7 @@ static void execute(uint64_t n) {
g_nr_guest_inst ++;
trace_and_difftest(&s, cpu.pc);
if (wp_eval_all()) {
puts(s.logbuf);
puts(logbuf[logbuf_rear]);
break;
}
if (nemu_state.state != NEMU_RUNNING) break;
@ -121,13 +125,16 @@ void cpu_exec(uint64_t n) {
switch (nemu_state.state) {
case NEMU_RUNNING: nemu_state.state = NEMU_STOP; break;
case NEMU_END: case NEMU_ABORT:
case NEMU_END: case NEMU_ABORT: {
Log("nemu: %s at pc = " FMT_WORD,
(nemu_state.state == NEMU_ABORT ? ANSI_FMT("ABORT", ANSI_FG_RED) :
(nemu_state.halt_ret == 0 ? ANSI_FMT("HIT GOOD TRAP", ANSI_FG_GREEN) :
ANSI_FMT("HIT BAD TRAP", ANSI_FG_RED))),
nemu_state.halt_pc);
// fall through
if(nemu_state.halt_ret != 0) {
log_itrace_print();
}
} // fall through
case NEMU_QUIT: statistic();
}
}

View file

@ -18,7 +18,10 @@
#include "../local-include/reg.h"
bool isa_difftest_checkregs(CPU_state *ref_r, vaddr_t pc) {
return false;
for(int i = 0; i < MUXDEF(CONFIG_RVE, 16, 32); i++) {
if(!difftest_check_reg(reg_name(i), pc, ref_r->gpr[i], gpr(i))) return false;
}
return true;
}
void isa_difftest_attach() {

View file

@ -13,11 +13,14 @@
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include "common.h"
#include <common.h>
#include "local-include/reg.h"
#include "macro.h"
#include <cpu/cpu.h>
#include <cpu/ifetch.h>
#include <cpu/decode.h>
#include <ftrace.h>
#include <utils.h>
#define R(i) gpr(i)
#define Mr vaddr_read
@ -54,11 +57,23 @@ static void decode_operand(Decode *s, int *rd, word_t *src1, word_t *src2,
static void do_branch(Decode *s, bool condition, word_t offset) {
if (condition) {
puts(s->logbuf);
// puts(s->logbuf[s->logbuf_rear]);
s->dnpc = s->pc + offset;
}
}
#ifdef CONFIG_FTRACE
static void ftrace_jalr(Decode *s, int rd, vaddr_t dst) {
uint32_t i = s->isa.inst.val;
int rs1 = BITS(i, 19, 15);
if(rs1 == 1 && rd == 0) {
ftrace_return(s->pc, dst);
} else {
ftrace_call(s->pc, dst);
}
}
#endif
static int decode_exec(Decode *s) {
int rd = 0;
word_t src1 = 0, src2 = 0, imm = 0;
@ -74,8 +89,12 @@ static int decode_exec(Decode *s) {
INSTPAT("??????? ????? ????? ??? ????? 01101 11", lui , U, R(rd) = imm);
INSTPAT("??????? ????? ????? ??? ????? 00101 11", auipc , U, R(rd) = s->pc + imm);
INSTPAT("??????? ????? ????? ??? ????? 11011 11", jal , J, do {s->dnpc = s->pc + imm; R(rd) = s->pc + 4; } while(0));
INSTPAT("??????? ????? ????? ??? ????? 11001 11", jalr , I, do {s->dnpc = src1 + imm; R(rd) = s->pc + 4; } while(0));
INSTPAT("??????? ????? ????? ??? ????? 11011 11", jal , J, do {
s->dnpc = s->pc + imm; R(rd) = s->pc + 4;
IFDEF(CONFIG_FTRACE, ftrace_call(s->pc, s->pc + imm)); } while(0));
INSTPAT("??????? ????? ????? ??? ????? 11001 11", jalr , I, do {
s->dnpc = src1 + imm; R(rd) = s->pc + 4;
IFDEF(CONFIG_FTRACE, ftrace_jalr(s, rd, src1 + imm)); } while(0));
INSTPAT("??????? ????? ????? 000 ????? 11000 11", beq , B, do_branch(s, src1 == src2, imm));
INSTPAT("??????? ????? ????? 001 ????? 11000 11", bne , B, do_branch(s, src1 != src2, imm));
INSTPAT("??????? ????? ????? 100 ????? 11000 11", blt , B, do_branch(s, (sword_t)src1 < (sword_t)src2, imm));

View file

@ -13,6 +13,8 @@
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include "common.h"
#include "debug.h"
#include <memory/host.h>
#include <memory/paddr.h>
#include <device/mmio.h>
@ -23,6 +25,11 @@ static uint8_t *pmem = NULL;
#else // CONFIG_PMEM_GARRAY
static uint8_t pmem[CONFIG_MSIZE] PG_ALIGN = {};
#endif
#ifdef CONFIG_MTRACE
static word_t mtrace_start[CONFIG_MTRACE_RANGE_MAX] = {0};
static word_t mtrace_end[CONFIG_MTRACE_RANGE_MAX] = {0};
static int range_count = 0;
#endif
uint8_t* guest_to_host(paddr_t paddr) { return pmem + paddr - CONFIG_MBASE; }
paddr_t host_to_guest(uint8_t *haddr) { return haddr - pmem + CONFIG_MBASE; }
@ -41,23 +48,58 @@ static void out_of_bound(paddr_t addr) {
addr, PMEM_LEFT, PMEM_RIGHT, cpu.pc);
}
#ifdef CONFIG_MTRACE
static void mtrace_print(char type, word_t addr, int len, word_t data) {
for (int i = 0; i < range_count; i++)
if (addr <= mtrace_end[i] && addr >= mtrace_start[i] ) {
Trace("Mem %c " FMT_PADDR "%d D " FMT_PADDR, type, addr, len, data);
break;
}
}
#endif
void init_mem() {
#if defined(CONFIG_PMEM_MALLOC)
pmem = malloc(CONFIG_MSIZE);
assert(pmem);
#endif
#ifdef CONFIG_MTRACE
char range[sizeof(CONFIG_MTRACE_RANGE)] = CONFIG_MTRACE_RANGE;
char *saveptr, *ptr;
ptr = strtok_r(range, ",", &saveptr);
for (range_count = 0; range_count < CONFIG_MTRACE_RANGE_MAX; ) {
word_t start, end;
Assert(sscanf(ptr, FMT_PADDR "-" FMT_PADDR, &start, &end) == 2, "Config option MTRACE_RANGE has wrong format");
mtrace_start[range_count] = start;
mtrace_end[range_count] = end;
range_count++;
ptr = strtok_r(NULL, ",", &saveptr);
if (!ptr) break;
}
Trace("MTRACE ranges: ");
for (int i = 0; i < range_count; i++) {
Trace("[0x%x, 0x%x]", mtrace_start[i], mtrace_end[i]);
}
#endif
IFDEF(CONFIG_MEM_RANDOM, memset(pmem, rand(), CONFIG_MSIZE));
Log("physical memory area [" FMT_PADDR ", " FMT_PADDR "]", PMEM_LEFT, PMEM_RIGHT);
}
word_t paddr_read(paddr_t addr, int len) {
if (likely(in_pmem(addr))) return pmem_read(addr, len);
IFDEF(CONFIG_DEVICE, return mmio_read(addr, len));
word_t result = 0;
if (likely(in_pmem(addr))) { result = pmem_read(addr, len); goto mtrace;}
IFDEF(CONFIG_DEVICE, result = mmio_read(addr, len); goto mtrace)
out_of_bound(addr);
return 0;
mtrace:
IFDEF(CONFIG_MTRACE, mtrace_print('R', addr, len, result));
return result;
}
void paddr_write(paddr_t addr, int len, word_t data) {
IFDEF(CONFIG_MTRACE, mtrace_print('W', addr, len, data));
if (likely(in_pmem(addr))) { pmem_write(addr, len, data); return; }
IFDEF(CONFIG_DEVICE, mmio_write(addr, len, data); return);
out_of_bound(addr);

View file

@ -15,6 +15,7 @@
#include <isa.h>
#include <memory/paddr.h>
#include <utils.h>
void init_rand();
void init_log(const char *log_file);
@ -40,6 +41,7 @@ static void welcome() {
void sdb_set_batch_mode();
static char *log_file = NULL;
static char *elf_file = NULL;
static char *diff_so_file = NULL;
static char *img_file = NULL;
static int difftest_port = 1234;
@ -72,6 +74,7 @@ static int parse_args(int argc, char *argv[]) {
{"log" , required_argument, NULL, 'l'},
{"diff" , required_argument, NULL, 'd'},
{"port" , required_argument, NULL, 'p'},
{"elf" , required_argument, NULL, 'f'},
{"help" , no_argument , NULL, 'h'},
{0 , 0 , NULL, 0 },
};
@ -82,6 +85,7 @@ static int parse_args(int argc, char *argv[]) {
case 'p': sscanf(optarg, "%d", &difftest_port); break;
case 'l': log_file = optarg; break;
case 'd': diff_so_file = optarg; break;
case 'f': elf_file = optarg; break;
case 1: img_file = optarg; return 0;
default:
printf("Usage: %s [OPTION...] IMAGE [args]\n\n", argv[0]);
@ -89,6 +93,7 @@ static int parse_args(int argc, char *argv[]) {
printf("\t-l,--log=FILE output log to FILE\n");
printf("\t-d,--diff=REF_SO run DiffTest with reference REF_SO\n");
printf("\t-p,--port=PORT run DiffTest with port PORT\n");
printf("\t-f,--elf=FILE elf file with debug info\n");
printf("\n");
exit(0);
}
@ -126,6 +131,16 @@ void init_monitor(int argc, char *argv[]) {
/* Initialize the simple debugger. */
init_sdb();
// printf("elf_file: %s\n", elf_file);
if(elf_file != NULL) {
#ifdef CONFIG_FTRACE
void init_elf(const char *path);
init_elf(elf_file);
#else
Warning("Elf file provided, but ftrace not turned on. Ignoring elf file.");
#endif
}
#ifndef CONFIG_ISA_loongarch32r
IFDEF(CONFIG_ITRACE, init_disasm(
MUXDEF(CONFIG_ISA_x86, "i686",

View file

@ -7,6 +7,7 @@
}
%{
#include <common.h>
#include <utils.h>
#include <isa.h>
#include <stdio.h>
#include <stdlib.h>

124
nemu/src/utils/ftrace.c Normal file
View file

@ -0,0 +1,124 @@
#include <assert.h>
#include <common.h>
#include <elf.h>
#include <ftrace.h>
#include <utils.h>
// Put this into another file
#ifdef CONFIG_FTRACE
static vaddr_t ftrace_stack[CONFIG_FTRACE_STACK_SIZE] = {0};
static vaddr_t ftrace_stack_len = 0;
func_t *func_table = NULL;
int func_table_len = 0, func_table_size = 8;
static int cmp_func_t(const void *a, const void *b) {
return ((func_t *)a)->start > ((func_t *)b)->start;
}
static func_t *get_func(vaddr_t addr) {
int l = 0, r = func_table_len - 1;
while(l <= r) {
int mid = (l + r) / 2;
if(func_table[mid].start <= addr) l = mid + 1;
else r = mid - 1;
}
return l == 0 ? NULL : &func_table[l - 1];
}
void init_elf(const char *path) {
FILE *elf_file = fopen(path, "rb");
Elf32_Ehdr header;
Elf32_Shdr section_header[200], *psh;
func_table = (func_t *)calloc(func_table_size, sizeof(func_t));
assert(func_table);
FAILED_GOTO(failed_header, fread(&header, sizeof(Elf32_Ehdr), 1, elf_file) <= 0);
FAILED_GOTO(failed_header, fseek(elf_file, header.e_shoff, SEEK_SET) != 0);
FAILED_GOTO(failed_header, fread(section_header, header.e_shentsize, header.e_shnum, elf_file) <= 0);
char *shstrtab = calloc(1, section_header[header.e_shstrndx].sh_size);
FAILED_GOTO(failed_shstrtab, fseek(elf_file, section_header[header.e_shstrndx].sh_offset, SEEK_SET) != 0);
FAILED_GOTO(failed_shstrtab, fread(shstrtab, section_header[header.e_shstrndx].sh_size, 1, elf_file) <= 0);
Elf32_Shdr *symtab = NULL, *strtab = NULL;
for(int i = 0; i < header.e_shnum; i++) {
psh = section_header + i;
if (psh->sh_type == SHT_SYMTAB) {
symtab = psh;
} else if (psh->sh_type == SHT_STRTAB && strncmp(shstrtab + psh->sh_name, ".strtab", 8) == 0) {
strtab = psh;
}
}
int sym_length = symtab->sh_size / sizeof(Elf32_Sym);
Elf32_Sym *sym = calloc(sym_length, sizeof(Elf32_Sym));
assert(sym);
FAILED_GOTO(failed_funcname, fseek(elf_file, symtab->sh_offset, SEEK_SET) != 0);
FAILED_GOTO(failed_funcname, fread(sym, sizeof(Elf32_Sym), sym_length, elf_file) <= 0);
for(int j = 0; j < sym_length; j++) {
if(ELF32_ST_TYPE(sym[j].st_info) != STT_FUNC) continue;
// Only read function type symbol
func_t *f = &func_table[func_table_len];
char *func = (char *)malloc(30);
FAILED_GOTO(failed_funcname, fseek(elf_file, strtab->sh_offset + sym[j].st_name, SEEK_SET) != 0);
FAILED_GOTO(failed_funcname, fgets(func, 30, elf_file) <= 0);
f->start = sym[j].st_value;
f->len = sym[j].st_size;
f->name = func;
++func_table_len;
if(func_table_len >= func_table_size) {
Assert(func_table_size * 2 > func_table_size, "Function table exceed memory limit");
func_table_size *= 2;
func_table = realloc(func_table, func_table_size * sizeof(func_t));
Assert(func_table, "Function table exceed memory limit");
}
}
qsort(func_table, func_table_len, sizeof(func_t), cmp_func_t);
goto success;
success:
free(sym);
free(shstrtab);
return;
failed_funcname:
free(sym);
failed_shstrtab:
free(shstrtab);
failed_header:
for(int i = 0; i < func_table_len; i++) {
func_t *f = &func_table[i];
if(f->name) { free(f->name); }
}
free(func_table);
Error("Failed reading elf file");
return;
}
void ftrace_call(vaddr_t pc, vaddr_t addr) {
func_t *f = get_func(addr);
Assert(ftrace_stack_len < CONFIG_FTRACE_STACK_SIZE,
"Ftrace stack exceed size limit, consider turn off ftrace or increase "
"FTRACE_STACK_SIZE.");
ftrace_stack[ftrace_stack_len] = pc + 4;
Trace("%*s0x%x call 0x%x <%s+0x%x>", ftrace_stack_len, "", pc, addr,
f == NULL ? "???" : f->name, addr - f->start);
ftrace_stack_len++;
}
void ftrace_return(vaddr_t pc, vaddr_t addr) {
--ftrace_stack_len;
for (; addr != ftrace_stack[ftrace_stack_len] && ftrace_stack_len >= 0;
ftrace_stack_len--) {
vaddr_t tco_addr = ftrace_stack[ftrace_stack_len];
func_t *f = get_func(tco_addr);
Trace("%*s0x%x ret 0x%x <%s+0x%x> (TCO)", ftrace_stack_len, "", pc, tco_addr,
f == NULL ? "???" : f->name, tco_addr - f->start);
}
func_t *f = get_func(addr);
Trace("%*s0x%x ret 0x%x <%s+0x%x>", ftrace_stack_len, "", pc, addr,
f == NULL ? "???" : f->name, addr - f->start);
}
#endif

View file

@ -14,6 +14,7 @@
***************************************************************************************/
#include <common.h>
#include <utils.h>
extern uint64_t g_nr_guest_inst;
@ -35,3 +36,18 @@ bool log_enable() {
(g_nr_guest_inst <= CONFIG_TRACE_END), false);
}
#endif
IFDEF(CONFIG_ITRACE, char logbuf[CONFIG_ITRACE_BUFFER][128]);
IFDEF(CONFIG_ITRACE, int logbuf_rear);
#ifdef CONFIG_ITRACE
void log_itrace_print() {
puts("ITRACE buffer:");
for (int i = (logbuf_rear + 1) % CONFIG_ITRACE_BUFFER; i != logbuf_rear; i = (i + 1) % CONFIG_ITRACE_BUFFER) {
if (logbuf[i][0] == '\0') continue;
puts(logbuf[i]);
}
puts("Current command:");
puts(logbuf[logbuf_rear]);
}
#endif