在linux内核里有这么一个函数
long void probe_kernel_write(*dst, void *src, size_t size)
故名意思,他就是探测内存是否可以写入,如果出错则返回非0
在STUB中我们经常要使用这么一个函数去替代memcpy
因为我们没法判断GDB要求地址的是否可以写入
在 arm下,该函数每次写入前都会调用
access_ok(VERIFY_READ, src, 1)
#define access_ok(type,addr,size) (__range_ok(addr,size) == 0)
判断当前地址是否可以写入
但显然,运行LINUX的设备并没有我们rtos设备需要运行在flash上的特点
所以他的probe_kernel_write只是copy_to_user而已
range_ok也只是检测地址是否超出了进程空间
并不检测出我们设备写入flash的错误
那怎么解决?
这里我看到一个非常有意思的办法
static long probe_kernel_write(void *dst, void *src, size_t size)
{
int i = 0;
char *dst_ptr = (char *)dst;
char *src_ptr = (char *)src;
gdb_mem_fault_handler = &&err;
for (i = 0; i<size; i++) {
*(dst_ptr++) = *(src_ptr++);
}
<pre name="code" class="cpp"> gdb_mem_fault_handler = (void *)0;
return 0;
err:
gdb_mem_fault_handler = (void *)0;
return -1;
}
上面这个函数是怎么实现判断地址是否可以写入的呢?
主要在这里
gdb_mem_fault_handler = &&err;
不清楚?
那我们看看dabt函数
void rt_hw_trap_dabt(struct rt_hw_register *regs)
{
#ifdef RT_USING_GDB
if (gdb_mem_fault_handler) {
regs->pc = (unsigned long)gdb_mem_fault_handler;
return;
}
#endif
rt_hw_show_register(regs);
rt_kprintf("data abort\n");
rt_kprintf("thread %.*s stack:\n", RT_NAME_MAX, rt_current_thread->name);
#ifdef RT_USING_FINSH
list_thread();
#endif
rt_hw_cpu_shutdown();
}
对 就是把dabt异常的返回地址设置到我们的err上去
这样就直接跳过了中间的操作部分
然后告诉我们写入错误
工程已经放出
可以参考readme-zh.txt在BBB板上运行
https://code.csdn.net/wzyy2/gdbstub4rtt
就是汇编部分没有能力,写的太丑陋了=.=