前几篇都是讲述了使用GDK7和NanoCode来调试内核的方法,本篇继续学习:
使用NanoCode来远程调试目标机GDK7的应用程序
分别通过“附加到进程”和“创建新进程”的方式来调试
注:
请将主机和目标机连接在同一个局域网内。
由于受限于tty进制,通过“创建新进程”的方式无法调试交互式或者带UI的程序。(本篇调试自己编译的readelf程序)
准备工作:
目标价GDK7需要使用新版本的ndsrv模块,请至http://advdbg.org/gdk/resource.aspx下载新版本,安装到目标机(使用systemctl status | grep ndsrv 查询服务是否在运行);
主机NanoCode需要使用1.1.0或以上版本;
准备被调试的程序(如果没有,这里使用了一个简单c++程序来调试,请复制出来保存到main.cpp,然后编译:g++ -g main.cpp -o main),请使用-g编译,带调试信息。
将执行程序main复制在目标机上,
同时将main放置在主机c:\temp\app下(目录可换),main.cpp放置在主机d:\dbg-source\main下(目录可换),用于解析符号和定位源代码。
#include <stdio.h>
#include <iostream>
#include <string>
#include <vector>
int sub(int a, int b) {
return a - b;
}
int add(int a, int b) {
return a + b;
}
void split_string(const std::string& input, char splitter, std::vector<std::string>& vec){
vec.clear();
if(input.empty())
return;
std::string::size_type begin = 0, pos =input.find(splitter);
while(pos != std::string::npos){
std::string tmp = input.substr(begin, pos - begin);
if(!tmp.empty()){
vec.push_back(tmp);
}
begin = pos + 1;
pos = input.find(splitter, begin);
}
if(begin < input.size()){
vec.push_back(input.substr(begin));
}
}
void usage() {
std::cout << "Usage:" << std::endl;
std::cout << "q - Exit app" << std::endl;
std::cout << "h - Show usage" << std::endl;
std::cout << "sub - Execute sub(a, b) function" << std::endl;
std::cout << "add - Execute add(a, b) function" << std::endl;
}
static const char* s_ver = "1.0";
int main() {
std::cout << "c++ example version:" << s_ver << std::endl;
usage();
int result = 0;
std::string input;
std::vector<std::string> vec;
for(; ;) {
std::cout << "Please input commnd:";
getline(std::cin, input);
split_string(input, ' ', vec);
if(vec[0] == "q"){
break;
} else if(vec[0] == "h"){
usage();
}else if (vec[0] == "add"){
if(vec.size() < 3){
std::cout << "Err: less paramter(add x y)" << std::endl;
continue;
}
int x = atoi(vec[1].c_str());
int y = atoi(vec[2].c_str());
result = add(x, y);
std::cout << "Add Result:" << result << std::endl;
} else if (vec[0] == "sub"){
if(vec.size() < 3){
std::cout << "Err: less paramter(sub x y)" << std::endl;
continue;
}
int x = atoi(vec[1].c_str());
int y= atoi(vec[2].c_str());
result = sub(x, y);
std::cout << "Sub Result:" << result << std::endl;
} else {
std::cout << "Err: Unknown command:" << vec[0] << std::endl;
usage();
}
}
std::cout << "App exits, bye." << std::endl;
return 0;
}
开始调试:
调试正在运行的进程
查看目标机ip地址;
在目标机控制台启动main程序,显示如下:
在主机端启动NanoCode;
在NanoCode里设置目标机的ip和port,并且连接到目标机(如果没有连接成功,将会报错),操作如下:
输入(tcp:port=200,server=目标ip)端口固定,点击“Connect”;
- 在NanoCode里选择被调试的远程程序,操作如下:
- 至此,已经挂上并中断下远端Ubuntu的main程序了;
此时,main程序已被挂起;
下面,开始设置符号路径和源文件路径;
.sympath+ c:\temp\app
.srcpath+ d:\dbg-source\main
查询main的符号
x main!*
可以看出,列出了好多stl的很多符号
调试main的sub函数
x main!sub // 查找函数地址
bp 地址 // 对函数地址下断点
重新g起来;
在目标机main程序下触发sub函数,输入sub 2 1,然后回车,成功断下,并且源代码也自动打开;
- 然后可以单步执行,查看寄存器,变量来调试了
~
调试新创建的进程–调试readelf
下载binutils,从https://ftp.gnu.org/gnu/binutils/下载,在ubuntu上编译,然后将readelf和源码复制一份到主机端,用于解析符号和源码调试 。
主机NanoCode连接到目标机,如上步骤1,重新设置:在NanoCode里设置目标机的ip和port,并且连接到目标机(如果没有连接成功,将会报错)。
在NanoCode里File->Open Executable…输入远程程序命令,或者使用历史记录,这里没有带任何参数,readelf打印帮助之后,就会自动退出了。
- 点击确认,然后设置符合和源码路径
- 然后查找函数,下断点,我们在main函数下断点
- 然后输入g,重新跑起来,程序自动断下,同时源码也自动打开
- 查看一下寄存器和临时变量
- 至此,可以继续调试其他了。
总结:
主要使用NanoCode远程调试Ubuntu上的应用程序;
不足:当调试完一个实例之后,下次调试又需要重新连接一次目标机;
不足:使用“创建新进程”的方式,暂时无法调试交互式或者带UI的程序;
待续。。。
最后编辑:沈根成 更新时间:2024-12-09 10:54