南京大学ics pa实验O

cs
Author

dd21

Published

December 5, 2022

https://github.com/GeeeekExplorer/NJU-ICS/blob/master/pa2018_fall/nemu/src/monitor/expr.c ># PA0 编译NEMU

fatal error: readline/readline.h: No such file or directory
sudo apt-get install libreadline-dev

安装的工具

apt-get install build-essential    # build-essential packages, include binary utilities, gcc, make, and so on
apt-get install man                # on-line reference manual
apt-get install gcc-doc            # on-line reference manual for gcc
apt-get install gdb                # GNU debugger
apt-get install git                # revision control system
apt-get install libreadline-dev    # a library used later
apt-get install libsdl2-dev        # a library used later
apt-get install llvm               # llvm project, which contains libraries used later
: error: ‘class llvm::MCInstPrinter’ has no member named ‘setPrintBranchImmAsAddress’

修改llvm的版本

sudo apt autoremove llvm-10
sudo apt install llvm-12
cd /usr/bin
sudo ln -s /usr/lib/llvm-12/bin/llvm-config  llvm-config

PA1 深入了解代码框架

  • 这里的pa是2020的isa-x86的pa
  • 首先是编译项目
  • 运行项目
  • 哦豁,不出意外是出意外了assert….(问题不大, 只有有报错信息问题就不大)

尝试解决assert报错

// 编译
ubuntu@VM-12-14-ubuntu:~/ics/ics2020/nemu$ make -B


Building x86-nemu-interpreter
+ CC src/device/audio.c
+ CC src/device/io/map.c
+ CC src/device/io/port-io.c
+ CC src/device/io/mmio.c
+ CC src/device/device.c
+ CC src/device/timer.c
+ CC src/device/serial.c
+ CC src/device/intr.c
....
+ LD build/x86-nemu-interpreter


// 运行
ubuntu@VM-12-14-ubuntu:~/ics/ics2020/nemu$ make run

// 报错
Building x86-nemu-interpreter
make -C /home/ubuntu/ics/ics2020/nemu/tools/kvm-diff 
make[1]: Entering directory '/home/ubuntu/ics/ics2020/nemu/tools/kvm-diff'
make[1]: Nothing to be done for 'app'.
make[1]: Leaving directory '/home/ubuntu/ics/ics2020/nemu/tools/kvm-diff'
./build/x86-nemu-interpreter --log=./build/nemu-log.txt --diff=/home/ubuntu/ics/ics2020/nemu/tools/kvm-diff/build/x86-kvm-so 
x86-nemu-interpreter: src/isa/x86/reg.c:20: reg_test: Assertion `reg_w(i) == (sample[i] & 0xffff)' failed.
make: *** [Makefile:108: run] Aborted (core dumped)
  • 查看src/isa/x86/reg.c:20:
  1 #include <isa.h>
  2 #include <stdlib.h>
  3 #include <time.h>
  4 #include "local-include/reg.h"
  5 
  6 const char *regsl[] = {"eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"};
  7 const char *regsw[] = {"ax", "cx", "dx", "bx", "sp", "bp", "si", "di"};
  8 const char *regsb[] = {"al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"};
  9 
 10 void reg_test() {
 11   srand(time(0));
 12   word_t sample[8];
 13   word_t pc_sample = rand();
 14   cpu.pc = pc_sample;
 15 
 16   int i;
 17   for (i = R_EAX; i <= R_EDI; i ++) {
 18     sample[i] = rand();
 19     reg_l(i) = sample[i];
 // 问题出在这里, 可是这几个宏有点折磨了, 盲猜是不是数据越界了
 [20]     assert(reg_w(i) == (sample[i] & 0xffff));
 21   }
  • 看到这宏定义有点折磨, 无从下手, 想起来一个好东西gcc -E, 嘿嘿, 这下人肉展开是不可能的, 直接安排
ubuntu@VM-12-14-ubuntu:~/ics/ics2020/nemu$ gcc -E ./src/isa/x86/reg.c 

# 1 "./src/isa/x86/reg.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "./src/isa/x86/reg.c"
./src/isa/x86/reg.c:1:10: fatal error: isa.h: No such file or directory
    1 | #include <isa.h>
      |          ^~~~~~~
compilation terminated.
  • 啊这, 我又麻了, 果然没有这么简单, 单独gcc -E是不行了, 依赖的文件都得加上才行, 可是这个脚本命令有点不会写啊, 来cat一下jyy的Makefile
// -E 我们都懂的, 可是-MF是什么,google一下,这里我是废物, 我又被google到的中文结果吸引进去了
@$(CC) $(CFLAGS) -E -MF /dev/null $< | \
    grep -ve '^#' | \
    clang-format - > $(basename $@).i

gcc -MF $< - 看完之后我又行了, 不就是建立个文件夹, 然后把每个.c的文件都预编译成.i文件, 我又拿捏了, 走着

ubuntu@VM-12-14-ubuntu:~/ics/ics2020/nemu$ make -B

Building x86-nemu-interpreter
+ CC src/device/audio.c
/bin/sh: 3: clang-format: Permission denied
make: *** [Makefile:81: build/obj-x86-interpreter/device/audio.o] Error 127
  • 啊这,啊这. 怎么直接都无法编译了, 定睛一看, Permission denied, 这我熟, 直接掏出祖传sudo
  • sudo make -B
ubuntu@VM-12-14-ubuntu:~/ics/ics2020/nemu$ sudo make -B

Building x86-nemu-interpreter
+ CC src/device/audio.c
/bin/sh: 3: clang-format: not found
make: *** [Makefile:81: build/obj-x86-interpreter/device/audio.o] Error 127
  • 通往pa1完成的道路上充满了坎坷, 说到底还是太菜了, 好在linux的报错信息太perfect了, clang-format: not found, easy, 这种小问题还是可以的直接sudo apt-get install clang-format
ubuntu@VM-12-14-ubuntu:~/ics/ics2020/nemu$ sudo apt-get install clang-format


Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following NEW packages will be installed:
  clang-format
0 upgraded, 1 newly installed, 0 to remove and 251 not upgraded.
Need to get 0 B/3,272 B of archives.
After this operation, 29.7 kB of additional disk space will be used.
Selecting previously unselected package clang-format.
(Reading database ... 143254 files and directories currently installed.)
Preparing to unpack .../clang-format_1%3a10.0-50~exp1_amd64.deb ...
Unpacking clang-format (1:10.0-50~exp1) ...
Setting up clang-format (1:10.0-50~exp1) ...
Processing triggers for man-db (2.9.1-1) ...
  • 冲冲冲…
  • sudo make -B
  • 又看到了熟悉的命令行信息+cc…, 奶思情况好转起来了
  • 直接冲到reg.i里面看看到底是个啥情况
// 找到reg.i
vim $(fzf)

reg.i

   1 
   2 
   3 typedef unsigned char __u_char;
   4 typedef unsigned short int __u_short;
   5 typedef unsigned int __u_int;
   6 typedef unsigned long int __u_long;
    ...
  46 typedef long int __clock_t;
  47 typedef unsigned long int __rlim_t;
  48 typedef unsigned long int __rlim64_t;
  49 typedef unsigned int __id_t;
  50 typedef long int __time_t;
  • 诶,窝草,怎么满屏的定义, 不慌不慌, 直接搜索函数reg_test , 嘿嘿好起来了.又看到了熟悉的代码
2066 const char *regsl[] = {"eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"};
2067 const char *regsw[] = {"ax", "cx", "dx", "bx", "sp", "bp", "si", "di"};
2068 const char *regsb[] = {"al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"};
2069 
2070 void reg_test() {
2071   srand(time(0));
2072   word_t sample[8];
2073   word_t pc_sample = rand();
2074   cpu.pc = pc_sample;
2075 
2076   int i;
2077   for (i = R_EAX; i <= R_EDI; i++) {
2078     sample[i] = rand();
2079     (cpu.gpr[check_reg_index(i)]._32) = sample[i];
2080 
2081     ((void)sizeof(
2082          ((cpu.gpr[check_reg_index(i)]._16) == (sample[i] & 0xffff)) ? 1 : 0),
2083      __extension__({
2084        if ((cpu.gpr[check_reg_index(i)]._16) == (sample[i] & 0xffff))
2085          ;
2086        else
2087          __assert_fail("reg_w(i) == (sample[i] & 0xffff)", "src/isa/x86/reg.c",
2088                        20, __extension__ __PRETTY_FUNCTION__);
2089      }));
2090   }

我擦, 我在搞什么飞机, 胡乱分析系统, 好家伙, jyy老师直接给出了ans. 强行分析一波. 唉, 这波说明在操作前看README的重要性. 在这里插入图片描述 - 好家伙, 我是真的服了我了,没有困难制造困难,代码就这么几行,我愣是没看到,只需要重新修改下就行, 我还在苦思冥想该怎么写, 怎么老是测试不过, 原来贴心的jyy老是早就猜到了我的水平,让我改改代码就完事了,大意了。

x86.h修改如下

typedef struct
{
  union{
    union {
      uint32_t _32;
      uint16_t _16;
      uint8_t _8[2];
    } gpr[8];
    
    struct{
      rtlreg_t eax, ecx, edx, ebx, esp, ebp, esi, edi;
    };
  };
  vaddr_t pc;
} x86_CPU_state;
  • 接着冲冲冲
  • make -B -j8 在这里插入图片描述
  • oh oh oh oh oh….

运行第一个客户程序

单步执行:

  • si [N]
  • 让程序单步执行, 这里有个小bug,不过也不算小bug,需要打开调试的宏DEBUGcommon.h中, 否则无法查看单步执行后的几寄存器的效果 在这里插入图片描述

ui.c

static int cmd_si(char *args) {
  // strtok is split string with specify symbol 
  // strtok(args,"")
  int step;
  
  if(args == NULL) step=1;
  // format string and move to a new vable  
  else sscanf(args,"%d",&step);
  
  // excute num
  cpu_exec(step);
  return 0;
}

ui.c> cmd_table

 { "si", "Debug by step NEMU", cmd_si },
  • 这个单步调试很关键哦, 后续的内存扫描需要用到这里作为校验,刚开始自己直接忽略了,吃了大亏,出来混还是的还的。 在这里插入图片描述 > ### 打印程序(寄存器)状态 > - 就是打印寄存器中的数据 > - 仿照上面的案例,修改cmd_table, 建立cmd_info函数

这里调用了reg.c中的isa_reg_display记得导入头文件

#include  "memory/vaddr.h"

void isa_reg_display() {
  for (int i = R_EAX; i < R_EDI; i++)
  {
    printf("$%s\t0x%08x\n", regsl[i] ,reg_l(i));
  }
  printf("$pc\t0x%08x\n",cpu.pc);
}

ui.c

static int cmd_info(char* args){
  
  // show register 
  if (args[0] == 'r') isa_reg_display();
  
  // show watch pointer
  else if(args[0] == 'w') TODO();
 
  return 0;
}

ui.c> cmd_table

 { "info", "info r-->show reg\ninfo w-->show watch pointer memory", cmd_info },
  • 注意这里的info是使用的info r进行测试,后面的info w暂时先搁置,先搞后面的扫描内存 在这里插入图片描述 >### 扫描内存(2)
  • 这里可有点弯弯绕,我最初的想法是通过传递进来的地址,然后直接按照16进制数进行数据的解析,好家伙, 我想的是真复杂了(好吧,我承认我又没有认真看手册,手册里面都说了,前面我们都看了内存是怎么设计的。。。。),vaddr_read 害。。

在这里插入图片描述 - 还是熟悉的套路:

ui.c> cmd_table

{ "x", "show memory from 0xxxx", cmd_x }

ui.c - 第一个参数是扫描的长度, 第二个参数是起始位置

static int cmd_x(char* args){
  uint32_t len;
  uint32_t addr;

  char* N    =  strtok(NULL," ");
  char* EXPR =  strtok(NULL," ");

  sscanf(N,"%d",&len);
  sscanf(EXPR,"%x",&addr);

  for(int i=addr;i<addr+(len*4);i+=4){
    word_t value = vaddr_read(i,4);
    printf("$0x%08x:\t0x%08x\n", i,value);
  }
  
  return 0;
}
  • 测试:

在这里插入图片描述

gdb中文参考:https://wizardforcel.gitbooks.io/100-gdb-tips/content/examine-memory.html

表达式求值

  • 正则表达式
  • expr.h &expr.c
  • 正则表达式的C语言使用

正则表达式在线测试: https://c.runoob.com/front-end/854/

正则表达式代码参考地址: https://www.ibm.com/docs/en/i/7.4?topic=functions-regcomp-compile-regular-expression - 正则表达式的基本使用 regcomp()

#include <regex.h>
int regcomp(regex_t *preg, const char *pattern, int cflags);

regexec()

参考链接: https://blog.csdn.net/weixin_46499713/article/details/125154268 https://blog.csdn.net/weixin_43877657/article/details/109068930?spm=1001.2014.3001.5502