# 2017q3 Homework4 (sandbox)
###### tags: `sysprog2017` `dev_record`
contributed by <`HMKRL`, `HTYISABUG`>
---
## gprof
- 代碼剖析工具
- 能幫助找出諸如函式執行時間, 執行次數等資訊
- 無法測量 kernal space 的花費時間
- 詳細操作參閱 `man gprof`
---
## 實作 moxiebox 環境的 fibonacci 數列
不先試試什麼都不會知道
先寫了含 `-i`, `--input` 參數的 `fib-iterative.c`
修改 `tests/Makefile` 以編譯自己的程式
```shell
/home/hty/x-tools/moxie-none-moxiebox/lib/gcc/moxie-none-moxiebox/7.2.0/../../../../moxie-none-moxiebox/lib/libc.a(lib_a-writer.o): In function `_write_r':
/home/hty/Downloads/build-toolchain/.build/moxie-none-moxiebox/src/newlib/newlib/libc/reent/writer.c:58: undefined reference to `_write'
/home/hty/x-tools/moxie-none-moxiebox/lib/gcc/moxie-none-moxiebox/7.2.0/../../../../moxie-none-moxiebox/lib/libc.a(lib_a-closer.o): In function `_close_r':
/home/hty/Downloads/build-toolchain/.build/moxie-none-moxiebox/src/newlib/newlib/libc/reent/closer.c:53: undefined reference to `_close'
/home/hty/x-tools/moxie-none-moxiebox/lib/gcc/moxie-none-moxiebox/7.2.0/../../../../moxie-none-moxiebox/lib/libc.a(lib_a-lseekr.o): In function `_lseek_r':
/home/hty/Downloads/build-toolchain/.build/moxie-none-moxiebox/src/newlib/newlib/libc/reent/lseekr.c:58: undefined reference to `_lseek'
/home/hty/x-tools/moxie-none-moxiebox/lib/gcc/moxie-none-moxiebox/7.2.0/../../../../moxie-none-moxiebox/lib/libc.a(lib_a-readr.o): In function `_read_r':
/home/hty/Downloads/build-toolchain/.build/moxie-none-moxiebox/src/newlib/newlib/libc/reent/readr.c:58: undefined reference to `_read'
/home/hty/x-tools/moxie-none-moxiebox/lib/gcc/moxie-none-moxiebox/7.2.0/../../../../moxie-none-moxiebox/lib/libc.a(lib_a-sbrkr.o): In function `_sbrk_r':
/home/hty/Downloads/build-toolchain/.build/moxie-none-moxiebox/src/newlib/newlib/libc/reent/sbrkr.c:58: undefined reference to `_sbrk'
/home/hty/x-tools/moxie-none-moxiebox/lib/gcc/moxie-none-moxiebox/7.2.0/../../../../moxie-none-moxiebox/lib/libc.a(lib_a-fstatr.o): In function `_fstat_r':
/home/hty/Downloads/build-toolchain/.build/moxie-none-moxiebox/src/newlib/newlib/libc/reent/fstatr.c:62: undefined reference to `_fstat'
/home/hty/x-tools/moxie-none-moxiebox/lib/gcc/moxie-none-moxiebox/7.2.0/../../../../moxie-none-moxiebox/lib/libc.a(lib_a-isattyr.o): In function `_isatty_r':
/home/hty/Downloads/build-toolchain/.build/moxie-none-moxiebox/src/newlib/newlib/libc/reent/isattyr.c:58: undefined reference to `_isatty'
collect2: error: ld returned 1 exit status
make: *** [fib-iterative] Error 1
```
編譯後馬上遇到一大堆錯誤
從錯誤訊息可以得知,這些錯誤是因為不存在相應 library 導致的
從 `sandbox-design.md` 得知 moxiebox 不提供任何 POSIX API
可用 library 只有以下幾種
- Runtime environment:
- moxie_memmap - Global variable, pointer to list of struct moxie_memory_map_ent, which describes the execution environment's input data.
- setreturn(3) - Pointer to environment's output data buffer. This is the data returned from the sandbox to the user.
- stdlib.h: abort(3), exit(3)
- string.h: memchr(3), memcmp(3), memcpy(3), memset(3)
- string.h: strchr(3), strcmp(3), strcpy(3), strlen(3), strncpy(3), strcpy(3), strstr(3)
- Runtime environment - crypto:
- sha256: sha256_init(), sha256_update(), sha256_final()
- System calls:
- mmap(2) - MAP_PRIVATE|MAP_ANONYMOUS to allocate heap memory.
- _exit(2) - End process
所有能使用的相關內容都被記載在 `runtime/sandboxrt.h`
----
在 `moxiebox` 中沒有 `malloc` 函式
作為替代方案, 可用 `mmap` 搭配 `MAP_PRIVATE | MAPANONYMOUS` 來配置記憶體
:::info
`mmap` 使用上大概可以根據**修改能見度**跟 **mapping 類型**分為四類
|能見度 \ 類型|file |MAP_ANONYMOUS|
|-----------|-----------------------|-------------|
|MAP_PRIVATE|以檔案內容初始化記憶體 |配置記憶體 |
|MAP_SHARED |memory mapping I/O, IPC|IPC |
:::
----
`moxie_memmap` 是來自 moxiebox 的輸入
為一陣列, 每一單元資料結構如下
```c
struct moxie_memory_map_ent {
void *addr;
size_t length;
char tags[32 - 4 - 4];
};
```
根據 `moxiebox` 的 usage
用 option `-d` 可以把文件載入為 input
:::info
這是 `moxiebox` 的 usage
`README.md`, `sandbox-design.md` 都沒有提到
打錯 option 時才無意中發現
```shell
Usage: src/sandbox [options]
options:
-E <directory> Add to executable hash search path list
-e <hash|pathname> Load specified Moxie executable into address space
-D <directory> Add to data hash search path list
-d <file> Load data into address space
-o <file> Output data to <file>. "-" for stdout
-t Enabling simulator tracing
-g <port> Wait for GDB connection on given port
-p <file> Write gprof formatted profile data to <file>
```
:::
----
### gdb stub
在使用 `gdb` 接入 `moxiebox` debug 的時候
程式發生了不正常跳過程式片段的行為

向老師詢問後, 確定是 `moxiebox` 內建的 `gdb stub` 有 bug
另外也發現執行 continue 時有錯誤行為:
```
(gdb) c
Continuing.
Program received signal SIGTRAP, Trace/breakpoint trap.
0x00001162 in _exit ()
```
程式結束,但 gdb 仍收到 `SIGTRAP`
追蹤程式碼並檢查 gdb stub:
```shell
$ grep -r gdb
src/moxie.h:40: gdb/config/moxie/tm-moxie.h file in the REGISTER_NAMES macro. */
src/sandbox.cc:188: uint32_t &gdbPort)
src/sandbox.cc:236: gdbPort = atoi(optarg);
src/sandbox.cc:366:static int gdb_main_loop(uint32_t &gdbPort, machine &mach)
src/sandbox.cc:383: serv_addr.sin_port = htons(gdbPort);
src/sandbox.cc:547: uint32_t gdbPort = 0;
src/sandbox.cc:549: sandboxInit(mach, argc, argv, outFilename, gmonFilename, gdbPort);
src/sandbox.cc:551: if (gdbPort)
src/sandbox.cc:552: gdb_main_loop(gdbPort, mach);
```
得知 gdb stub 的程式本體在函式 `gdb_main_loop` 中
參考 [gdb remote protocal](http://davis.lbl.gov/Manuals/GDB/gdb_31.html) 並對照程式碼實作
發現其中幾個部份留有 `FIXME` :
c (continue) 部份:
```
case 'c':
wrc = write(newsockfd, "+", 1);
sim_resume(mach);
// FIXME.. assuming BREAK for now
sendGdbReply(newsockfd, "S05");
mach.cpu.asregs.regs[16] -= 2;
i += 4;
```
`S05` 對應 linux signal table 即為 SIGTRAP
應該將指令的回傳訊息改為正確的 signal.
對照程式碼後,確認程式收到的 signal 會存在 `cpu.asregs.exception` 中
```cpp
case 0x1: /* SYS_exit */
{
cpu.asregs.exception = SIGQUIT;
break;
}
```
因此搭配原有的 `word2hex` 將正確的 signal 回傳:
```cpp
case 'c':
wrc = write(newsockfd, "+", 1);
sim_resume(mach);
/* send correct signal to remote gdb */
word2hex(reply, mach.cpu.asregs.exception);
reply[5] = 'S';
sendGdbReply(newsockfd, &reply[5]);
```
m 指令處的 FIXME 也用同樣的方法實作錯誤確認:
```cpp
char *p = (char *) mach.physaddr(addr, length);
if (!p) {
word2hex(reply, errno);
strncpy(reply, &reply[6], 2);
goto cmd_m_out;
}
```
不同點在於 m 指令接受的回傳只有以 hex 表示的 errno 值
### gdb command file
可以將 gdb 指令寫在檔案中,在常需要重複行為(例如做 remote debugging 所需的 `target remote` 指令)
`gdb_cmd`:
```
target remote :9999
break main
run
```
讀取command file:
`(gdb) source gdb_cmd`
----
在編寫 fibonacci 的過程中
一開始在使用 `-o` option 時會產生錯誤
```shell
Sim exception 7 (Bus error)
```
參考 `tests/sha256.c` 修改程式碼, 發現是 `mmap` 的 `length` 參數出了問題
本來閱讀參考書^[Michael Kerrisk. (2016). The Linux Programming Interface 國際中文版.]了解到, 就算 `length` 沒給到 page size
系統在分配記憶體時也會以 page size 為單位分配
但是依據這邊的程式行為來看 `moxiebox` 的 `mmap` 似乎不會自動延展記憶體配置
才會導致在 `setreturn` 時產生 Bus error
因此將 `length` 修改為以 `runtime/sandboxrt.h` 提供的 `MACH_PAGE_SIZE` 為單位
就成功修正這個錯誤了
---
## 移植 constant-time-sorts 到 moxiebox
在開始移植之前要先確認非 constant-execution-time 的 sort 在 `moxiebox` 會有什麼行為
參考來自 github 的樣本^[https://github.com/ktslabbie/constant-time-sorts]編寫 selection , insertion , bubble sort
在這個步驟, 我們遇到了超出預想的錯誤
----
```c=
static void swap(int *a, int *b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
void selectionsort(int array[], int n)
{
int min;
for (int i = 0; i < n; ++i) {
min = i;
for (int j = i; j < n; j++)
if (array[min] > array[j]) min = j;
swap(&array[i], &array[min]);
}
}
```
這是一段 selection sort 的程式碼
這段程式碼在 `moxiebox` 中執行時會產生 `Sim exception 7 (Bus error)`
藉由 `gdb` 觀察錯誤點時會得到以下錯誤訊息
```shell
Program received signal SIGEMT, Emulation trap.
0x00001430 in swap (b=0x3304, a=0x2b08) at sort.c:49
49 *a = *b;
```
我們得到 `SIGEMT` 這個 signal 導致了程式的錯誤
上網查詢, `SIGEMT` 出現的情況為「虛擬環境接收到不被識別的指令」
為了得知究竟哪裡產生這個錯誤, 我們藉由 grep 挖掘程式碼中有關 `SIGEMT` 的片段
```shell
$ grep -ir SIGEMT
```
結論是程式碼中根本沒有任何相關的片段
因此我們判斷可能是 gdb stub 在傳輸接收時有問題
於是加上些觀察用程式碼,將 gdb stub 的回複字串印出來觀察:
```shell
+$S07#BA
```
可以發現實際上被傳送的是 `SIGBUS(7)` , 但接收端卻將它辨認為 `SIGEMT(?)`
----
進一步藉由 gdb 觀察產生錯誤的程式碼片段
發現錯誤是產生在 `st.l` 這個組語指令執行的時候
```shell
(gdb) x/8i $pc-4
0x15ea <insertionsort+220>: ldo.l $r1, 0xfff4($fp)
=> 0x15ee <insertionsort+224>: st.l ($r0), $r1
0x15f0 <insertionsort+226>: ldo.l $r0, 0xfffc($fp)
0x15f4 <insertionsort+230>: inc $r0, 0x1
0x15f6 <insertionsort+232>: sto.l 0xfffc($fp), $r0
0x15fa <insertionsort+236>: ldo.l $r1, 0xfffc($fp)
0x15fe <insertionsort+240>: ldo.l $r0, 0x10($fp)
0x1602 <insertionsort+244>: cmp $r1, $r0
```
藉由 grep 挖掘到 `moxie.cc` 中實作了 `st.l` 的功能
```c
case 0x0b: /* st.l */
{
int dest = (inst >> 4) & 0xf;
int val = inst & 0xf;
TRACE("st.l");
wlat(mach, cpu.asregs.regs[dest], cpu.asregs.regs[val]);
} break;
```
順著所用函式往下挖
```c
/* Write a 4 byte value to memory. */
static void INLINE wlat(machine &mach, word addr, word v)
{
if (!mach.write32(addr, v))
mach.cpu.asregs.exception = SIGBUS;
}
```
可以看見 gdb stub 傳送的 `SIGBUS` 是在這邊被設置的
這說明 `mach.writes2(addr, v)` 產生了錯誤
```c
bool machine::write32(uint32_t addr, uint32_t val)
{
uint32_t *paddr = (uint32_t *) physaddr(addr, 4, true);
if (!paddr)
return false;
*paddr = val;
return true;
}
```
挖掘的成果到這裡為止, 接下來為何會發生錯誤尚未釐清