操作比纯调试器

 返回

 

    学习比纯调试器一些典型操作. :

   1) 构建工程

   2) 抓取进程日志

   3) 从进程日志发现BUG

   4) python运行到断点

   5) 打印文本、变量

   6) 观察变量修改历史

   7) GO调试跟踪

   8) 详细LOG日志

   9) 过滤日志

 10) PV配对检查

 11耗时统计

 12安卓LAN调试

 13嵌入式LAN调试

 14STM32|AVR32|CCS单片机调试

      

    构建工程、抓取进程日志、过滤、设断点、打印文本、观察变量、详细日志、PV配对观察几个经典动作反复运用,不知不觉您就成了比纯调试器高手。

   

 

构建工程

 1shell批处理文件中比纯调试器构建多个工程(bm.exe不用bd.sh) 

 

A

echo off

bm.exe  build e:\exer\Cproj 

bm.exe  build e:\exer\Dproj

echo on

因为e:\exer\myproj下有源代码,含调试信息。这种方式在后台打包,后台构建,后台调试特别有用。因为大项目是在后台构建、打包的。如果运行bd.exe,还能抓出BUG

 

B  

echo off

bm.exe  build  e:\exer\Eproj    modX  

echo on

    因为e:\exer\Eproj\modX下有源代码,所以bd.exe不但构建工程,而且含e:\exer\Eproj\modX子路径调试信息。如果e:\exer\Eproj\modXX工程师编写,e:\exer\Eproj\modYY工程师编写,多人协作,部分调试就变得可能。

 

2)命令下构建工程( 运行bd.bat | bd.sh 下的命令行)

 

bd > build  e:\exer\myproj      modX

构建myproj工程,处于e:\exer\myproj \ modX目录下的代码可以看到进程日志,其他部分看不到进程日志

bd > build  e:\exer\myproj    

    构建myproj工程,全部代码均可以调试。

 

3)命令下构建和调试指定文件( 运行bd.bat | bd.sh 下的命令行)

 

bd > build  e:\exer\myproj     a.c  b.c

   构建myproj工程,但只对a.c b.c 可以察看调试日志和变量,这样调试的好处是调试进程,但运行速度几乎不受影响。定位BUG也筛选得比较清楚。

   

bd > build  e:\exer\myproj     SetData*.go

   构建myproj工程并筛选对SetData打头的go代码进行调试跟踪。运行速度快。

   另外, 单片机的中断代码, 嵌入式摄像头数据帧的采集, 实时性高, 只能对指定文件调试,在高速运行中抓取执行轨迹和变量。

 

4) 例子

      构建命令

  

  构建中:

 

  构建完成:

 

 

用户不用修改工程即可部署到WEB服务器上。

 

 

抓取进程日志

使用flash命令:

bd > flash           -> 抓取进程日志, 只显示最后256

bd > flash –s a.txt   -> 抓取进程日志, 只保存最后60000

bd > flash a*.java   -s a.txt  -> 只保存a*.java 的进程日志

bd > flash c.c : 78 –s b.txt -> 只保存a.c 78行所在函数日志

示例:

构建并运行:

 

 

抓取进程日志:

 

 

 

从进程日志中发现BUG

示例:

程序运行无反应,看上面的进程日志,看到delete pMainFrame;主对象被释放了,比较奇怪,再看源代码:

原因是pMainFrame对象没创建就使用了。修改为:

       CMainFrame *pMainFrame;

 pMainFrame = new …

       if ( !pMainFrame || !pMainFrame->LoadFrame(..)便OK了。

 

看下一张抓取的进程日志:

程序没弹出窗体,抓取的进程日志,显示return FALSE 失败返回,是if ( pDocTemplate ) 产生return FALSE动作,应该是条件判断反了。修改为:

     if ( !pDocTemplate )

            return FALSE;

OK了。所以,看着进程日志修改BUG比手工”BUG靠谱多了。

运行到断点

 

bins加断点命令,如果代码无崩溃,最好加上断点,加上断点的进程运行更快.

 

bins     a.py  10  //  插入a.py  10行处断点

 运行python,在断点处停止了:

抓取进程日志后,按F3热键退出断点,进程继续运行

 

 

打印文本变量值

 

在代码中插入bprint(  string )函数后用bd.exe构建,就可打印了。

bd.exe 构建

运行

 

图中看到打印了3行。

 

 

 

观察变量修改历史

bwatch()函数观察特定变量的修改历史, data_type 是基本数据类型 , 或其数组

语法:

C:      bwatch(   "title" , var_address , data_len );

:    bwatch(   "Person" , &p , char , 128 );   // C can watch a whole struct 

 

GO:     bwatch(   "title" , var_name , data_type , data_len )

:    bwatch(   "PersonNum" , p.num , int , 8 )

:    bwatch(   "PersonName" , &(p.name[0]) , rune , 10 )

:    bwatch(   "Wives" , p.wives , [8]string , 64 )

 

C# & JAVA :   bwatch( "title" , class_name , obj , member_name , data_type , data_len );

:

bwatch( "title" , Person , this , p.age , int , 4 );  // if bwatch (p.age) defined in Person.java , obj == this

bwatch( "title" , Person , Person , p.age , int , 4 ); // if p.age is static int , obj1.age == obj2.age== class.age

bwatch( "title" , null , null , k , int , 4 ); // error , stack var k can not bwatch( ... )

bwatch( "title" , Person , chongqing , p.age , int , 0 );// close bwatch(p.age) , if data_len set 0

 

Go: bwatch( "title" , class_name , obj , member_name , data_type , data_len );

:

bwatch( "age" , persion , p , age , int , 8 )

...

bwatch( "age" , 0 , 0 , 0, 0 , 0 )

bwatch( "manwives" , Man , p , wife , [8]string , 128 )

bwatch( "manwives" , Man , p , wife , [8]string , 0 )

 

 

 

构建:

运行,然后用vlog 命令抓取值:

可以看出,g_MainWindows_num 值共4个值。

在单片机中,中断频繁,bwatch()只能查看到断点的值,不能查看值的变化.

 

JAVA C#,bwatch()只能查看对象的值变化过程,语法如下:

bwatch( name , class , object , member , datatype , datalen );// open bwatch

bwatch( name , class , object , member , datatype , 0 ); // close bwatch

datatype 是基本数据类型及其数组

 

:

Person p = new Person( 20 , 40 );

p.age = 30;

p.wife={"linda", "rose", "" ,"" };

bwatch( "AGE" , Person , p , age , int , 4 );

bwatch( "Wives" , Person , p , wife , String[] , 128 );

...

bwatch( "Wives" , Person , p , wife , String[] , 0 );

bwatch( "AGE" , Person , p , age , int , 0 );

 

GoLang调试示例

以下是调试Go抓图

build之前在代码中插入bwatch()

build 

 

build ok [GO_BUILD_PATH][GO_BUILD_OUTPUT]自动写入bdebug.ini

触发断点后, vlog -s v.txt, 显示变量a的修改历史

flash -s a.txt , hello.exe 运行日志的102行尾部

 

详细进程日志

lon  命令后,解除了只60000行日志的限制,从进程第一行开始记录:

运行D:\exer\VC2015\MFCApp\Debug\MFCApp.exe, 一阵操作后,用clog –s c.txt命令,以下是开始的进程日志:

以下是进程的第一行开始日志:

以下是进程当前日志:

可以看出,进程从第一行开始,已运行了402861行了。

 

 

过滤进程日志

 

 

过滤进程日志,去掉非关键日志,就能简化BUG的发现,

只看MFCApp.exe的入口代码文件:

clog mfcapp.cpp –s d.txt

 

只查看classview.cpp OnCreate()函数的进程日志,OnCreate()函数包含第77行,所以用clog classview.cpp 77 命令:

20行,从clog20万行,过滤只观看其中20行,各种过滤让BUG的发现是一个愉快的过程。

 

PV配对观察

编程中大量严格配对的PV函数操作,如open close , connect disconnect. CreateObj , DestroyObjmalloc free , new delete,用PV技术观察配对. malloc free , new delete已自动PV跟踪不需配置,其他的PV跟踪须在bdebug.ini声明。

运行bd.exe

再运行D:\exer\VC2015\MFCApp\Debug\MFCApp.exe

关闭MFCApp.exe,用PV命令看对象的释放:

 

 

可以看到有多达14个对象没有调用delete释放,或没有显式释放。这是编程的忌讳。好程序应该对象不用就显式、完全地释放。

 

 

耗时统计

timeon命令

运行:

然后查看进程日志,已包含每行语句执行的时间:

可以看到,mfcapp.cpp 76CWinAppEx::InitInstance()耗时376个时间片,mfcapp.cpp 101LoadStdProfileSettings(4)耗时241个时间片,软件性能优化可以从这两个函数开始检查代码并优化。

 

 

 

Android

 

组网:

将家庭小型WIFI网关组成局域网,PC用网线连接, android手机用WIFI密码连接。测得比纯调试器PC IP192.168.0.100 android手机IP192.168.0.101ping :

构建APP

请注意,Please assign pc lan ip:192.168.0.100

构建成功:

USB线连接手机和PC,将outputs\apk\debug\app-debug.apk下载到安卓,在手机上,找到app-debug.apk文件,点击安装,生成btrueantest

点击btrueantest图标,运行

抓取进程日志, 下面是App第一行起的日志:

下面是App最后几行的日志

根据进程日志、断点、打印变量值等方式,就可以调试安卓APP了。调试、运行都很流畅。

 

嵌入式Linux

 

首先,嵌入式LINUX设备和宿主PC机(含bd.exe)在同一个LAN网上:

宿主PC  ip:   192.168.0.101

 

嵌入式设备 ip   192.168.0.100

从宿主PC (192.168.0.101 ) ping 嵌入式LINUX设备(192.168.0.100

构建时,指定比纯调试器所在PCIP192.168.0.101

 

构建的程序download到嵌入式开发板:

 

运行开发板上程序embedtest.bin

 

抓取运行日志:

 

可以看到,embedtest.binbtcpservice.c 38因断言捕获,崩溃了。

[00084][listenimpl.c]下个断点,再次运行:

 

这个BUG怎么改?作为练习交给亲爱的您去完成.

 

STM32|AVR32|CCS单片机

 

构建

根据MCU的片内ram大小选择调试空间大小,缺省是中等(M),选择后,构建继续:

 

构建OK后,将执行文件D:\exer\uart1_interrupt\Obj\USART.axf烧写到单片机。

利用Keil UVision工具,点击上图中download按钮即开始烧写。

 

连接调试串口

connmcu命令

 

抓取进程日志:

插入一个断点:

利用比纯串口工具,查看串口输出:

这是被调试STM32程序的串口输出数据。

 

单片机空间的修改,以下是Ti CCS空间修改例子:

file: F28062.cmd

(1)   删除FLASHH FLASHG FLASHF , 把它们的容量全部合并到FLASHE

(2)   删除RAML3 ,把RAML3容量合并到RAML2

(3)   各类地址段指向大FLASH段或大RAM

修改后,空白RAM|FLASH得以利用,空间增大,bd.exe构建mcu工程就OK了。

以下是构建成功界面: