操作比纯调试器
学习比纯调试器一些典型操作. :
1) 构建工程
2) 抓取进程日志
3) 从进程日志发现BUG
4) python运行到断点
5) 打印文本、变量
6) 观察变量修改历史
7) GO调试跟踪
8) 详细LOG日志
9) 过滤日志
10) PV配对检查
11)耗时统计
12)安卓LAN调试
13)嵌入式LAN调试
构建工程、抓取进程日志、过滤、设断点、打印文本、观察变量、详细日志、PV配对观察几个经典动作反复运用,不知不觉您就成了比纯调试器高手。
1)shell批处理文件中比纯调试器构建多个工程(用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\modX是X工程师编写,e:\exer\Eproj\modY是Y工程师编写,多人协作,部分调试就变得可能。
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行所在函数日志
示例:
构建并运行:
抓取进程日志:
示例:
程序运行无反应,看上面的进程日志,看到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 );
以下是调试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行日志的限制,从进程第一行开始记录:
以下是进程的第一行开始日志:
以下是进程当前日志:
可以看出,进程从第一行开始,已运行了402861行了。
过滤进程日志,去掉非关键日志,就能简化BUG的发现,
只看MFCApp.exe的入口代码文件:
clog
mfcapp.cpp –s d.txt
只查看classview.cpp OnCreate()函数的进程日志,OnCreate()函数包含第77行,所以用clog classview.cpp 77 命令:
有20行,从clog共20万行,过滤只观看其中20行,各种过滤让BUG的发现是一个愉快的过程。
编程中大量严格配对的PV函数操作,如open close , connect disconnect. CreateObj , DestroyObj,malloc 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 76行CWinAppEx::InitInstance()耗时376个时间片,mfcapp.cpp 101行LoadStdProfileSettings(4)耗时241个时间片,软件性能优化可以从这两个函数开始检查代码并优化。
组网:
将家庭小型WIFI网关组成局域网,PC用网线连接, android手机用WIFI密码连接。测得比纯调试器PC IP为192.168.0.100 ,android手机IP为192.168.0.101,ping :
构建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设备和宿主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)
构建时,指定比纯调试器所在PC的IP:192.168.0.101
构建的程序download到嵌入式开发板:
运行开发板上程序embedtest.bin
抓取运行日志:
可以看到,embedtest.bin在btcpservice.c 38因断言捕获,崩溃了。
[00084][listenimpl.c]下个断点,再次运行:
这个BUG怎么改?作为练习交给亲爱的您去完成.
构建:
根据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了。
以下是构建成功界面: