---
# System prepended metadata

title: rv32emu trace code

---

# rv32emu trace code

###### tags: `Project`

by [\<ypaskell\>](https://github.com/ypaskell)

## 目標

完整了解 rv32emu 的 code

## Setup environment

### 1. Add debug flag to Makefile

Add `-g` in Makefile

```Makefile=
include mk/common.mk
include mk/toolchain.mk

OUT ?= build
BIN := $(OUT)/rv32emu

CFLAGS = -std=gnu99 -O2 -Wall -Wextra
CFLAGS += -Wno-unused-label -g    #<--- Add CFLAGS -g here
CFLAGS += -include src/common.h

# Set the default stack pointer
CFLAGS += -D DEFAULT_STACK_ADDR=0xFFFFF000

OBJS_EXT :=

# Control and Status Register (CSR)
ENABLE_Zicsr ?= 1
$(call set-feature, Zicsr)
```

### 2. Build debug build

```shell
make all
```

## Understanding elf files `hello.elf`

### Objdump `hello.elf`

Run `riscv32-unknown-elf-objdump -dhs build/hello.elf | less`

* `-d`: Display assembler contents of executable sections
* `-h`: Display the contents of the section headers
* `-s`: Display the full contents of all sections requested

```Text=
$ riscv32-unknown-elf-objdump -dhs build/hello.elf

build/hello.elf:     file format elf32-littleriscv

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         00000050  00000000  00000000  00001000  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .riscv.attributes 0000001a  00000000  00000000  00001050  2**0
                  CONTENTS, READONLY
Contents of section .text:
 0000 93020000 13035000 6f004000 13000000  ......P.o.@.....
 0010 63826202 93080004 13051000 97050000  c.b.............
 0020 93854502 1306d000 73000000 93821200  ..E.....s.......
 0030 6ff01ffe 9308d005 13050000 73000000  o...........s...
 0040 48656c6c 6f20576f 726c6421 0a000000  Hello World!....
Contents of section .riscv.attributes:
 0000 41190000 00726973 63760001 0f000000  A....riscv......
 0010 05727633 32693270 3100               .rv32i2p1.

Disassembly of section .text:

00000000 <.text>:
   0:	00000293          	li	t0,0
   4:	00500313          	li	t1,5
   8:	0040006f          	j	0xc
   c:	00000013          	nop
  10:	02628263          	beq	t0,t1,0x34
  14:	04000893          	li	a7,64
  18:	00100513          	li	a0,1
  1c:	00000597          	auipc	a1,0x0
  20:	02458593          	addi	a1,a1,36 # 0x40
  24:	00d00613          	li	a2,13
  28:	00000073          	ecall
  2c:	00128293          	addi	t0,t0,1
  30:	fe1ff06f          	j	0x10
  34:	05d00893          	li	a7,93
  38:	00000513          	li	a0,0
  3c:	00000073          	ecall
  40:	6548                	flw	fa0,12(a0)
  42:	6c6c                	flw	fa1,92(s0)
  44:	6f57206f          	j	0x72f38
  48:	6c72                	flw	fs8,28(sp)
  4a:	2164                	fld	fs1,192(a0)
  4c:	000a                	c.slli	zero,0x2
	...
```

### elf open

Run `riscv32-unknown-elf-readelf -h build/hello.elf`

```text=
$ riscv32-unknown-elf-readelf -h build/hello.elf
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           RISC-V
  Version:                           0x1
  Entry point address:               0x0
  Start of program headers:          52 (bytes into file)
  Start of section headers:          4240 (bytes into file)
  Flags:                             0x0
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         2
  Size of section headers:           40 (bytes)
  Number of section headers:         4
  Section header string table index: 3
```

上面的 Elf Header 是要在 rv32emu `elf_*` 的 function 處理的。

### Start using debugging tool (gdb or lldb)

我在 Apple Silicom M1 上跑，無法使用 gdb。但 lldb 和 gdb 大同小異，請自行轉換 Command

Navigate to main function

```text
(lldb) b main
Breakpoint 1: 25 locations.
(lldb) r
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
    frame #0: 0x000000010000bca4 rv32emu`main at main.c:112:5 [opt]
   109 	static bool parse_args(int argc, char **args)
   110 	{
   111 	    /* parse each argument in turn */
-> 112 	    for (int i = 1; i < argc; ++i) {
   113 	        const char *arg = args[i];
   114 	        /* parse flags */
   115 	        if (arg[0] == '-') {
   
(lldb) finish
Process 28894 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = step out
    frame #0: 0x000000010000bdf4 rv32emu`main(argc=<unavailable>, args=0x000000016fdff368) at main.c:209:18 [opt]
   206 	    }
   207
   208 	    /* open the ELF file from the file system */
-> 209 	    elf_t *elf = elf_new();
   210 	    if (!elf_open(elf, opt_prog_name)) {
   211 	        fprintf(stderr, "Unable to open ELF file '%s'\n", opt_prog_name);
   212 	        return 1;
```

Initialize `elf_t` for saving elf data

```text
(lldb) s
Process 28894 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = step in
    frame #0: 0x000000010000a81c rv32emu`elf_new at elf.c:137:16 [opt]
   134
   135 	elf_t *elf_new() 
   136 	{
-> 137 	    elf_t *e = malloc(sizeof(elf_t));
   138 	    e->hdr = NULL;
   139 	    e->raw_size = 0;
   140 	    e->symbols = map_init(int, char *, map_cmp_uint);
   141 	    e->raw_data = NULL;
   142 	    return e;
   143 	}
```

`elf_t` declared in `elf.c`

```cpp=
typedef struct elf_internal elf_t; // fron elf.h
struct elf_internal {
    const struct Elf32_Ehdr *hdr;
    uint32_t raw_size;
    uint8_t *raw_data;

    /* symbol table map: uint32_t -> (const char *) */
    map_t symbols;
};
```


```cpp=
bool elf_open(elf_t *e, const char *path)
{
bool elf_open(elf_t *e, const char *path)
{
    /* free previous memory */
    if (e->raw_data)
        release(e);

#if defined(USE_MMAP)
    int fd = open(path, O_RDONLY);
    if (fd < 0)
        return false;

    /* get file size */
    struct stat st;
    fstat(fd, &st);
    e->raw_size = st.st_size;

    /* map or unmap files or devices into memory.
     * The beginning of the file is ELF header.
     */
    e->raw_data = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
    if (e->raw_data == MAP_FAILED) {
        release(e);
        return false;
    }

#else  /* fallback to standard I/O text stream */
    FILE *f = fopen(path, "rb");
    if (!f)
        return false;

    /* get file size */
    fseek(f, 0, SEEK_END);
    e->raw_size = ftell(f);
    fseek(f, 0, SEEK_SET);
    if (e->raw_size == 0) {
        fclose(f);
        return false;
    }

    /* allocate memory */
    free(e->raw_data);
    e->raw_data = malloc(e->raw_size);

    /* read data into memory */
    const size_t r = fread(e->raw_data, 1, e->raw_size, f);
    fclose(f);
    if (r != e->raw_size) {
        release(e);
        return false;
    }
#endif /* USE_MMAP */

    /* point to the header */
    e->hdr = (const struct Elf32_Ehdr *) e->raw_data;

    /* check it is a valid ELF file */
    if (!is_valid(e)) {
        release(e);
        return false;
    }

    return true;
}
```

Q&A (2023/09/11)

* Question: 為什麼原本使用 fopen 現在使用 `mmap`.  [man mmap](https://man7.org/linux/man-pages/man2/mmap.2.html) ?
* Jserv: `mmap` 在開啟大檔案時會有優勢。On-demand paging。反之，fopen 遇到大檔案時，開啟時間較慢。
* Question: man `mmap` 説，mmap 是利用 virtual memory。Virtual Memory 在 Disk 不是會比較慢嗎。
* Jserv: virtual memory 不見得跟 disk 有關，請「不要」讀恐龍書來。[這本書可自由下載，品質比恐龍書好多了](https://pages.cs.wisc.edu/~remzi/OSTEP/)


[understanding mmap, the workhorse behind keeping memory access efficient in linux](https://www.youtube.com/watch?v=8hVLcyBkSXY)

`struct stat` - [man](https://man7.org/linux/man-pages/man2/stat.2.html)

```cpp=
struct stat {
    dev_t     st_dev;     /* ID of device containing file */
    ino_t     st_ino;     /* inode number */
    mode_t    st_mode;    /* protection */
    nlink_t   st_nlink;   /* number of hard links */
    uid_t     st_uid;     /* user ID of owner */
    gid_t     st_gid;     /* group ID of owner */
    dev_t     st_rdev;    /* device ID (if special file) */
    off_t     st_size;    /* total size, in bytes */
    blksize_t st_blksize; /* blocksize for file system I/O */
    blkcnt_t  st_blocks;  /* number of 512B blocks allocated */
    time_t    st_atime;   /* time of last access */
    time_t    st_mtime;   /* time of last modification */
    time_t    st_ctime;   /* time of last status change */
};
```



