算法旅人

2021年11月12日星期五

本周的MP重点在于学习使用GDB进行调试,这里贴一个GDB的官方介绍:

GNU symbolic debugger,简称「GDB 调试器」,是 Linux 平台下最常用的一款程序调试器。GDB 编译器通常以 gdb 命令的形式在终端(Shell)中使用

学会使用debugger进行逐行调试是很重要的编程基本功,就像我们在学习汇编语言时使用了LC3-tk 一样,本质上gdb也是带有追踪标记功能的调试工具,Pavol教授也坦言Lumetta他们实际上就是基于GDB设计的可视化的LC3 debugger。

或许有人会觉得使用GCC的编译就足以发现程序问题了,但实际上,我们常常会遇到三种【错误】:error, exception 和 bug,以及不一定会影响运行的warning(典中典:warning 不影响程序运行,不用太care)实际上,早在CS101伟烈教授就讲解了他们三者的区别:

很显然我们可以看到,最有危害的是bug , 即逻辑漏洞(错误)。逻辑错误指的是代码思路或者设计上的缺陷,程序出现逻辑错误的症状是:代码能够编译通过,没有语法错误,但是运行结果不对。对于这类错误,只能靠我们自己去发现和纠正。

C语言中文网就说到:对于初学者来说,学习调试可以增加编程的功力,能让我们更加了解自己的程序,比如变量是什么时候赋值的、内存是什么时候分配的,从而弥补学习的纰漏。调试是每个程序员必须掌握的基本技能,没有选择的余地!”

那么这里我们就先略过对GDB的概览介绍,研究一下本次MP的问题吧:

  1. MAKE文件有一个bug导致我们不能编译使用GDB【√】需要添加 -g Flag
  2. 第三个程序只有可执行文件,无法看到源码的条件下进行黑盒测试

注:黑盒测试又叫功能测试、数据驱动测试或基于需求规格说明书的功能测试。. 该类测试注重于测试软件的功能性需求。采用这种测试方法, 测试工程师把测试对象看作一个黑盒子,完全不考虑程序内部的逻辑结构和内部特性,只依据程序的《需求规格说明书》,检查程序的功能是否符合它的功能说明。. 测试工程师无需了解程序代码的内部构造,完全模拟软件产品的最终用户使用该软件,检查软件产品是否达到了用户的需求。. 黑盒测试方法能更好、更真实地从用户角度来考察被测系统的功能性需求实现情况。

3,第一个程序涉及到C语言main函数参数的概念:

不带参数的main 后的括号都是空括号。实际上,main函数可以带参数,这个参数可以认为是main函数的形式参数。C语言规定main函数的参数只能有两个,习惯上这两个参数写为argc和argv。因此,main函数的函数头可写为:
    main (argc,argv)
C语言还规定argc(第一个形参)必须是整型变量,argv(第二个形参)必须是指向字符串的指针数组。加上形参说明后,main函数的函数头应写为:
    main (int argc,char *argv[])

由于main函数不能被其它函数调用,因此不可能在程序内部取得实际值。那么,在何处把实参值赋予main函数的形参呢?实际上,main函数的参数值是从操作系统命令行上获得的。当我们要运行一个可执行文件时,在DOS提示符下键入文件名,再输入实际参数即可把这些实参传送到main的形参中去。
命令行的一般形式为:
    C:\>可执行文件名  参数  参数 ……; 
但是应该特别注意的是,main 的两个形参和命令行中的参数在位置上不是一一对应的。因为,main的形参只有二个,而命令行中的参数个数原则上未加限制。

argc参数表示了命令行中参数的个数(注意:文件名本身也算一个参数),argc的值是在输入命令行时由系统按实际参数的个数自动赋予的。

例如有命令行为:
    C:\>E24  BASIC  foxpro  FORTRAN
由于文件名E24本身也算一个参数,所以共有4个参数,因此argc取得的值为4。argv参数是字符串指针数组,其各元素值为命令行中各字符串(参数均按字符串处理)的首地址。 指针数组的长度即为参数个数。数组元素初值由系统自动赋予。其表示如图所示:

——引用自C语言中文网

这里就能看出,C和Python的显著不同,一个是指针,一个则是面对对象
当然,python也支持__main__这样的语法,以后会学到,蛮重要的,类与OOP
4, 素数问题:

这里看到了一个很好的知乎帖子,讲解如何求素数的数学原理

5种你不知道的素数的判断方法 - 知乎 (zhihu.com)https://zhuanlan.zhihu.com/p/104314640

5, 堆排序:Heap Sort

堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。堆排序可以说是一种利用堆的概念来排序的选择排序。分为两种方法:

  1. 大顶堆:每个节点的值都大于或等于其子节点的值,在堆排序算法中用于升序排列;
  2. 小顶堆:每个节点的值都小于或等于其子节点的值,在堆排序算法中用于降序排列;

堆排序的平均时间复杂度为 Ο(nlogn)。

——菜鸟教程

第三个sort程序的黑箱测试:

BUG在:应该是arr[n-1]而不是arr[n]!

array 从 0 开始计算索引!

以下是本次的report:

比较长,因为specific 里面需要复制粘贴我的g

;=======================================;
|   Machine Problem Seven
|       Worked By Wang Jie(Tony)
|      Netid: jiew5, ZJUid: 3200112404
|   Date: 2021.11.12
;=======================================;TASK DESCRTIPTION:In this MP, I need to write down the possible reason of 3 buggy C function.
To do so, I need GDB debugger to do the black box test. ==============================================================================
[FIRST: PrintRev.c]
0, Report
student@ece220-VM:~/jiew5/mp/mp7/printRev$ make
gcc -c -g -Wall -o pr_buggy.o pr_buggy.c 2> /dev/null #Here I add a -g flag in the Makefile
gcc -c -g -Wall -o prmain.o prmain.c
gcc pr_buggy.o prmain.o -o prev -gstudent@ece220-VM:~/jiew5/mp/mp7/printRev$ gdb prev -q  #Here I add a -q flag to skip the declearation of GDB
Reading symbols from prev...
-----------------------------------------|
1, Function Description:The function, consist of pr_buggy.c and prmain.c, is used to reverse the input string sentence.After 10 numbers counting down, the program asked "What's on the stack now?"
then print the reversed version and the length of string.Meanwhile, the main function use blank [ ] to seperate the input arguments and
it support multiple input.-----------------------------------------|
2, input case:<a> YZZ,YWW  #Chinese short name for "The story of Brave is never finished."(gdb) r YZZ,YWW
Starting program: /home/student/jiew5/mp/mp7/printRev/prev YZZ,YWW
9 8 7 6 5 4 3 2 1 0
What's on the stack now?"YZZ,YWW" reversed is "WWY,ZZY" (length 7)  #Correct1
[Inferior 1 (process 4007) exited normally]<b> ECE220 is so hard! (gdb) r ECE220 is soo hard!
Starting program: /home/student/jiew5/mp/mp7/printRev/prev ECE220 is so hard!
9 8 7 6 5 4 3 2 1 0
What's on the stack now?"ECE220" reversed is "022ECE" (length 32773)   #BUG1
9 8 7 6 5 4 3 2 1 0
What's on the stack now?"is" reversed is "si" (length 2)   #Correct2
9 8 7 6 5 4 3 2 1 0
What's on the stack now?"soo" reversed is "oos" (length 3) #Correct3
9 8 7 6 5 4 3 2 1 0
What's on the stack now?"hard!" reversed is "!drah" (length 32772) #BUG2
[Inferior 1 (process 4049) exited normally]<c> 12345 #Used to test 5 length str
(gdb) r 12345
Starting program: /home/student/jiew5/mp/mp7/printRev/prev 12345
9 8 7 6 5 4 3 2 1 0
What's on the stack now?"12345" reversed is "54321" (length 32772) #BUG3
[Inferior 1 (process 4293) exited normally]2, Reason of BUG:After examing the code, I find that in pr_buggy.c, there are an innitial error of
int32_t rest. It should be set as 0 at the beginning of code, otherwise when the recursive process ends,
we can't know what will be the starting rest, so the ending rest will be very large.3, How to solve it:Just simply change line #36 in pr_buggy.c
from     int32_t rest;
into     int32_t rest = 0;
Then every BUG input above works.
==============================================================================
[SECOND: primeNumber.c]
//The source code of is_prime.c is hidden.
//Doing Black box test can help us find the bug
1, Bug report:
gdb primeNumber
GNU gdb (Ubuntu 9.2-0ubuntu1~20.04) 9.2
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:<http://www.gnu.org/software/gdb/documentation/>.For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from primeNumber...
(gdb) r
Starting program: /home/student/jiew5/mp/mp7/primeNumber/primeNumber
2 is prime.
3 is prime.
4 is prime. #not a prime
5 is prime.
7 is prime.
9 is prime. #not a prime
11 is prime.
13 is prime.
17 is prime.
19 is prime.
23 is prime.
25 is prime.    #not a prime
29 is prime.
31 is prime.
37 is prime.
41 is prime.
43 is prime.
47 is prime.
49 is prime.    #not a prime
53 is prime.
59 is prime.
61 is prime.
67 is prime.
71 is prime.
73 is prime.
79 is prime.
83 is prime.
89 is prime.
97 is prime.
101 is prime.
103 is prime.
107 is prime.
109 is prime.
113 is prime.
121 is prime.   #not a prime
127 is prime.
131 is prime.
137 is prime.
139 is prime.
149 is prime.
151 is prime.
157 is prime.
163 is prime.
167 is prime.
169 is prime.   #not a prime
173 is prime.
179 is prime.
181 is prime.
191 is prime.
193 is prime.
197 is prime.
199 is prime.
211 is prime.
223 is prime.
227 is prime.
229 is prime.
233 is prime.
239 is prime.
241 is prime.
251 is prime.
257 is prime.
263 is prime.
269 is prime.
271 is prime.
277 is prime.
281 is prime.
283 is prime.
289 is prime.
293 is prime.
307 is prime.
311 is prime.
313 is prime.
317 is prime.
331 is prime.
337 is prime.
347 is prime.
349 is prime.
353 is prime.
359 is prime.
361 is prime.   #not a prime
367 is prime.
373 is prime.
379 is prime.
383 is prime.
389 is prime.
397 is prime.
401 is prime.
409 is prime.
419 is prime.
421 is prime.
431 is prime.
433 is prime.
439 is prime.
443 is prime.
449 is prime.
457 is prime.
461 is prime.
463 is prime.
467 is prime.
479 is prime.
487 is prime.
491 is prime.
499 is prime.
503 is prime.
509 is prime.
521 is prime.
523 is prime.
529 is prime.   #not a prime
541 is prime.
547 is prime.
557 is prime.
563 is prime.
569 is prime.
571 is prime.
577 is prime.
587 is prime.
593 is prime.
599 is prime.
601 is prime.
607 is prime.
613 is prime.
617 is prime.
619 is prime.
631 is prime.
641 is prime.
643 is prime.
647 is prime.
653 is prime.
659 is prime.
661 is prime.
673 is prime.
677 is prime.
683 is prime.
691 is prime.
701 is prime.
709 is prime.
719 is prime.
727 is prime.
733 is prime.
739 is prime.
743 is prime.
751 is prime.
757 is prime.
761 is prime.
769 is prime.
773 is prime.
787 is prime.
797 is prime.
809 is prime.
811 is prime.
821 is prime.
823 is prime.
827 is prime.
829 is prime.
839 is prime.
841 is prime.
853 is prime.
857 is prime.
859 is prime.
863 is prime.
877 is prime.
881 is prime.
883 is prime.
887 is prime.
907 is prime.
911 is prime.
919 is prime.
929 is prime.
937 is prime.
941 is prime.
947 is prime.
953 is prime.
961 is prime.
967 is prime.
971 is prime.
977 is prime.
983 is prime.
991 is prime.
997 is prime.
[Inferior 1 (process 2575) exited normally]BUG: some of check is wrongly output, there are not prime.
BUG Case: [4,9,25,49,121,169,361,529,...]
From mathmatical anlaysis, we know all of these cases are the square of prime.
And for efficiently checking whether a given number N is prime, we divide it between 2 to sqrt(N),
seeing if it can be divide excatly.
Here we set breakpoints and display check to see whether it works like my assumption:
(gdb) b main
Breakpoint 1 at 0x1139: file primeNumber.c, line 38.
(gdb) r
Starting program: /home/student/jiew5/mp/mp7/primeNumber/primeNumber Breakpoint 1, main () at primeNumber.c:38
38  {
(gdb) display check
1: check = 0
(gdb) watch check == 4
Hardware watchpoint 2: check == 4
(gdb) watch check == 9
Hardware watchpoint 3: check == 9
(gdb) watch check == 25
Hardware watchpoint 4: check == 25
(gdb) c
Continuing.
2 is prime.
3 is prime.Hardware watchpoint 2: check == 4Old value = 0
New value = 1
(gdb) n
4 is prime.
(gdb) c
Continuing.
5 is prime.
7 is prime.Hardware watchpoint 3: check == 9Old value = 0
New value = 1
0x0000555555555176 in main () at primeNumber.c:42
42      for (check = 2; 1000 > check; check++) {
1: check = 9
(gdb) c
Continuing.
9 is prime.Hardware watchpoint 3: check == 9Old value = 1
New value = 0
#... Repeating process2, Reason of BUG:By checking all of the check, we found that is_prime cannot know if [check] can be divided by
[sqrt(check)] exactly.
Therefore, we can guess the children function is_prime contains a comparison symbol error.
It should be <= sqrt(N) instead of < 3, How to solve it:Just simply change comparison symbol in is_prime.c
from     < sqrt(N)
into     <= sqrt(N)
Then every BUG input above works.
==============================================================================
[THIRD: sort]
//The source code of sortMain.c is hidden.
// It is astonishing that we don't have a main program... and there is a bug in it...
0, Function description:Seeing test1.txt and sort.c, we know the program first detect whether do we
input a txt file, if not it prints:"Usage: ./sort <input_file>"The main program first test the 1st line of input file, which is number N
receiving the length of array to be sorted. Then it calls heapify N times, sort the array and calls printArray to
print sorted array.----------------------------|
1, TEST case:
student@ece220-VM:~/jiew5/mp/mp7/sort$ gdb sort -q
Reading symbols from sort...
(gdb) r test1.txt
Starting program: /home/student/jiew5/mp/mp7/sort/sort test1.txt
1 3 9 12 13 15 18 19 22 23 29 41 45 51 58 96 97 99 100 117    #Seems it is correct output.
[Inferior 1 (process 2928) exited normally]
After running program many times..
1 3 9 12 13 13 15 18 19 22 23 29 41 45 51 58 96 97 99 100 # The biggest Number is lost, and we get another 13
Repeating test the program, we see the output of sort is totally random.Therefore, we can assume that there is a bug in the index method of main program,
which will cauase such a random case.
Then we can track arr[0], arr[19] and arr[20] to know whether my hypothesis is true. 2, Discription of deBUG:
I set 3 break points:
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x0000555555555477 <main+4>2       breakpoint     keep y   0x00005555555551c9 in swap at sort.c:33       breakpoint     keep y   0x0000555555555258 in heapify at sort.c:19
And after I run to heapify, I trace arr[0],arr[19] and arr[20]:
(gdb) display arr[0]
1: arr[0] = 97
(gdb) display arr[20]
2: arr[20] = 0
(gdb) display arr[19]
3: arr[19] = 0
However, since the total number of to be sorted number is 20, and the C language starts from zero 0,
the arr[20] should always not be used( Otherwise there will be strange value stored in its memory.
And we continue:
Breakpoint 3, heapify (arr=0x55555555a490, n=20, i=5) at sort.c:19
19  {
1: arr[0] = 1
2: arr[20] = 117   #We can see, arr[20] is used by main program!
3: arr[19] = 13
We can almost sure what is wrong, but we contine:Since the testing process is long, I continuely enter c to watch how the bottom of array changes:
Until:
Breakpoint 3, heapify (arr=0x55555555a49c, n=21845, i=1431676076) at sort.c:19
19  {
1: arr[0] = 99
2: arr[20] = 0
3: arr[19] = 129825
we can see there is a strange number in arr[19], while 20 is zero, then we can conclude that it must
a bug in the sortMain.o that uses a place of arr which should not be used.3, How to solve it:Not quite sure, it depends on the main prgram's writing styleMaybe we just need to simply change arr[n] to arr[n-1]?==============================================================================
Ps. In this MP, I always unconsciously used the annotation writing style and syntax similar to LC3, so I couldn't help using ; or //. It's very trance

不过嘛,我发现了教授的小尾巴,很显然,他们是伪造出了bug,好方便我们查找

太阴险了! :-(

ECE220生存指南[02] MP7: GDB 调试Debug相关推荐

  1. gdb 笔记(02)— gdb 调试执行(启动调试、添加参数、附加到进程、调试 core 文件)

    在编译程序时,使用 gcc 或者 g++ 时一定要加上 -g 选项,如 gcc -g -o hello hello.c 以便调试程序含有调试符号信息,从而能够正常调试程序.否则则会出现如下提示,导致不 ...

  2. linux嵌入式gdb调试指南,建立嵌入式gdb调试环境

    一.下载gdb-6.4.tar.gz源代码 http://ftp.gnu.org/gnu/gdb/ 二.编译 GDB #tar zxvf gdb-6.4.tar.gz 2.1.编译GDB Server ...

  3. ECE220生存指南[01]: MP6,从RGB到HSL

    算法旅人 2021年11月8日更新 物理课太无聊了,开始写一下博客来提提精神了. 本周的Machine Problem 要求我们实现以下四个函数: 1,convert_RGB_to_HSL //将PN ...

  4. ECE220生存指南[03]MP8: 递归函数实现油漆桶问题,Flood Fill with Recursion

    算法旅人 2021年11月20日 本周的MP依然是填写部分函数的形式--不得不说这种写部分子函数的MP确实很适合用于练习编写特定代码.同时,这个形式可以保证高度的独一无二性,上网查也找不到直接对应的答 ...

  5. GDB调试指南(入门,看这篇够了)

    写这篇文档的目的是对前面GDB的知识做一次总览,本文为GDB调试指南,参考GDB调试手册,目前已有的篇目: 启动调试 断点设置 查看源码 单步调试 查看变量 前言 GDB是Linux下非常好用且强大的 ...

  6. gdb 调试_GDB调试指南-源码查看

    前言 我们在调试过程中难免要对照源码进行查看,如果已经开始了调试,而查看源码或者编辑源码却要另外打开一个窗口,那未免显得太麻烦.文本将会介绍如何在GDB调试模式下查看源码或对源码进行编辑. 准备工作 ...

  7. GDB调试指南-单步调试

    前言 前面通过<启动调试>,<断点设置>,<变量查看>,我们已经了解了GDB基本的启动,设置断点,查看变量等,如果这些内容你还不知道,建议先回顾一下前面的内容.在启 ...

  8. gdb调试lua_gdb 调试入门,大牛写的高质量指南

    原标题:gdb 调试入门,大牛写的高质量指南 (点击上方公众号,可快速关注) 来源: 伯乐在线 - 道法子 如需转载,发送「转载」二字查看说明 没想到Brendan Gregg这样的大牛,会写出这样一 ...

  9. qemu debug linux内核,在QEMU环境中使用GDB调试Linux内核

    简介 对用户态进程,利用gdb调试代码是很方便的手段.而对于内核态的问题,可以利用crash等工具基于coredump文件进行调试.其实我们也可以利用一些手段对Linux内核代码进行gdb调试,qem ...

最新文章

  1. jsapi设计_一个简单API设计
  2. php和python哪个用了开发web好-php web与python web哪个好
  3. 非等高cell实战(01)-- 实现微博页面
  4. IPv6扩展头部 (三) 路由头部 Routing Header for IPv6
  5. 文件服务器 双机,文件服务器双机备份
  6. AWGN和Rayleigh信道下QPSK的误码率分析
  7. 使用socket创建服务器进程和客户端进程
  8. 怎样取消Windows 2003 server 意外关机提示
  9. 16进制转double dotnet_终于把计算机进制弄明白了!
  10. python列表操作符_python——列表操作符
  11. Linux学习总结(55)——Linux 运维常用脚本
  12. 机器学习技法2-Dual Support Vector Machine
  13. 访问win10的远程桌面(Remote Desktop)总是凭据或者用户密码错误
  14. BerkeleyDB
  15. k3 审核流程图_3金蝶K3操作流程图详解
  16. 分享:绘图不可不知的CAD经典技巧
  17. 教你4种压缩PDF让文档快速变小的方法
  18. 直方图python_Python数据可视化的例子——直方图和核密度曲线
  19. 易语言新手入门教程第十四课 - QQ自动登录器第二部分
  20. VM+Lamp环境搭建

热门文章

  1. 串口通信中一些常用的小工具
  2. 算法模板:动态规划之线性DP【沈七】
  3. Java生成名片式的二维码源码分享
  4. 速卖通AliExpress绑定连连跨境支付收款教程!
  5. UE4打包项目部署到Quest遇到的问题
  6. 汉语编程、中文编程、国产C语言-习语言4714(2016)版下载及教程
  7. Windows IDEA 字体美化
  8. 计算机视觉基础-图像处理-几何变换
  9. 行人重识别 度量学习
  10. 数据库设计的阶段及对应产物