1)监视点的结构体
typedef struct watchpoint {
int NO; //编号
struct watchpoint *next;
int value; //旧值,
int newvalue; //新值,
char type; //类型监视点w or断点b
char Enb; //是否开启
char str[32]; //被监视的表达式
/* TODO: Add more members if necessary */
} WP;
new_wp是从free链表中取一个结点给head链表,且将表达式、值赋给它,修改开关,并输出该节点的编号。运用正则表达式判断是否为断点,若是则type为b,否则为w,具体见下文断点处。
free_wp函数是遍历head链表直到找出对应NO的结点,从head中删除,添加到free链表中。同时修改类型、表达式、值、开关。
3)温故而知新
框架代码中定义wp_pool等变量时使用了关键字static,在此处的含义是静态全局变量,该变量只能被本文件中的函数调用,并且是全局变量,而不能被同一程序其他文件中的函数调用。在此处使用static是为了避免它被误修改。
代码如下:
在cpu-exec.c中:
/* TODO: check watchpoints here. */
int judge=judge_wp();
if(judge==-1)
{
nemu_state = NEMU_STOP;
printf("Triggered the monitoring point\n");
return;
}
在watchpoint.c中:
结果截图:
3)使用info w来打印监视点信息。这里在cmd_info中调用了函数print_wp(),代码如下:
void print_wp()
{
printf("Num\tType\tEnb \t\t Value\t\t What\n");
for(int i=0;i
结果截图:
3、删除监视点。在cmd_d中调用free_wp函数即可。
结果截图:
1)断点;
代码在上面已经贴出。运用正则表达式判断是否为断点格式:$eip==0x16进制数字,regcomp()函数编译正则表达式,执行成功返回0,则type为b,否则为w。
截图:
2)一点也不能长?
必须的。因为当我们在调试器中对代码的某一行设置断点时,会把这里本来指令的第一个字节保存起来,然后写入一条INT 3指令,机器码为0xcc,仅有一个字节,设置和取消断点时也需要保存和恢复一个字节。
断点机制不能正常工作。因为INT3断点将被调试进程中对应地址处的字节替换为0xcc,当int3指令的长度变成2个字节,其他指令同x86,会导致这里本来指令的第一个字节被2个字节所代替,空间不够,不正确。
3)随心所欲的断点。
将断点设置在指令的非首字节,就无法检测到断点。因为会检测函数的地址,读取它的第一个字节,判断是否等于0xCCH。
4)NEMU的前世今生。
模拟器emulator和调试器debugger的不同。我觉得dubugger是一个命令行调试工具,设置断点,调试程序,测试bug,然后emulator是一个载体,就是虚拟机,是一个独立的系统,不会对电脑本身的系统造成影响,我们可以借助它兼容不同的软件。
我觉得gdb和nemu中我们在实现的功能好像差不多,但是gdb是可以直接在函数某一行或是函数入口处设置断点,可以随便查看变量当前的值。
1)理解基础设施;
在调试上花费75h,简易调试器帮它节省50h。
2)查阅i386手册;
1、EFLAGS寄存器中的CF位是什么意思?
P34页中提到参阅附录c,CF是进位标志;
P419页中写到CF位:在最高位发生进位或者借位的时候将其置1,否则清零。
2、ModR/M字节是什么?
P241-243页。ModR/M由Mod,Reg/Opcode,R/M三部分组成。Mod是前两位,提供寄存器寻址和内存寻址,Reg/Opcode为345位,如果是Reg表示使用哪个寄存器,Opcode表示对group属性的Opcode进行补充;R/M为678位,与mod结合起来查图得8个寄存器和24个内存寻址
3、mov指令的具体格式是怎么样的?
P347页。格式是DEST ←SRC.
3)shell命令;
.c和.h文件有3994行代码,使用命令:
find . -name "*[.h|.cpp]" | xargs wc -l
和框架代码相比,在PA1中写了1008行代码;
log回转代码回到过去;除去空行之外, nemu/ 目录下的所有.c 和.h 文件总共有3308行代码。
find . –name “*[.cpp|.h]” | xargs grep “^.” | wc -l
-Wall 使GCC产生尽可能多的警告信息,取消编译操作,打印出编译时所有错误或警告信息。
-Werror 要求GCC将所有的警告当成错误进行处理,取消编译操作。
使用-Wall和-Werror就是为了找出存在的错误,尽可能地避免程序运行出错,优化程序。