记得上大学时,做C语言的程序都是用sdb来调试的;再后来有了gdb,同sdb差不多,不过就好用了很多。但终究还是有点遗憾。比如,程序里设计了几个函数,如果想测试下它们,就不得不再编写个测试函数,用各种可能的输入进行调用;测试完后,一般会删掉这段测试代码,如果是保留着,那下次修改了函数的参数接口,编译器就开始抱怨了,只好坚持维护那一段测试代码。当时我就在想,要是有个SHELL界面,让我直接运行那些函数就好了。这样就不用费尽写些测试代码,更别说维护了!
工作后,很多时候是做嵌入式系统,那丫可没有GDB,或者说GDB没那么容易用上。当然,更直接的挑战是,已经上线运行的系统,GDB就不用考虑了!除非我们提前考虑到哪些需要在CLI里提供debug信息,其它一切就都是黑盒子了!此外,客户可能有各种各样的想法,要求我们预制各类开关。通过CLI调整这些开关值当然可行,但总不是那么方便。我以前给电信做移动电话程控交换机,全国应用了数百套设备,每套设备都有自己的特殊配置。
怎么办才能做好呢?程序行为跟某个全局变量有关,但却没法查看那个变量当前的值;程序出错了,因为忘了某个初始化函数。这种时候,我们需要一个CSHELL接口,让程序里所有的全局变量,函数变得可以查看,修改和运行。当然,这一切都是自动完成的,准确点说,只要make就有了!
下载地址:
https://files.cnblogs.com/files/hhao020/cshell_prj.re0.001.rar
请解压后在Linux系统下编译(需要perl环境)。
CSHELL涉及Lex,Yacc,ELF解析等技术,以下为其实现过程:
1,编写cshell.l词法文件, cshell.y语法文件;
2, 使用Lex和Bison(Yacc)生成SHELL输入的解释文件(C源代码);
3,Make编译并第一次链接生成.out文件(符号表为空);
4,使用p_readelf.pl(调用readelf)生成符号表源文件;
5,Make第二次链接生成.out文件(含符号表);
注:CSHELL符号表并非ELF文件的符号表,具体可参见c_sym_table.c文件。
应用开发者,只需要链接CSHELL库和符号表,并在其程序中提供CSHELL的输入接口,就能够获得CSHELL的一切功能。
链接中的CSHELL运行起来,会是这个样子:
cshell_prj $ bin/linux.i64/user.exe
$7/> DemoVar1;
= 10 (0x620000000A) <SYM_DATA : size=4>
$11/> DemoCall2("my int var", 5);
input my int var=5
= 0 (0x0) <FUNCALL : size=0>
-><cmd/test.cmd
...............
CSHELL语法是C语言编程的一个子集,只help里的内置命令除外。使用有几个技巧:
1,函数调用最多支持10个参数,多了会被丢弃,结果嘛,呵呵~当然,可以改cshellfuns.c来调整;
2,调用时,少给了几个参数,会被默认为0,好好利用这个特性,比如打印实例函数!
3,可以添加变量,比如x=123;
4,可以多个表达式写一行,用分号;隔开;
5,可以将函数结果赋值给变量,如x=functioncall(...),当然,这时候的x必须先存在或是创建好;
6,可以批量运行,执行<script即可,比如执行链接里的脚本 <cmd/test.cmd
对于CSHELL希望作些定制的朋友,可以阅读cshellfuncs.c。原理很简单,就是将输入编程一个二叉树,左孩子右兄弟;实现时,考虑的细节还是蛮多的,必须的,要不就不好玩了!看明白这个cshellfuncs.c,又弄明白编译过程的朋友,可以留言索取lex词法文件和yacc语法文件。没上传,不影响任何使用,CSHELL是个开源代码,我不想被某个公司据为己有,你可以用,但不能剥夺别人用的权利。
当然,凡事有利必有害。CSHELL给你方便的同时,也让你的程序空间暴露在外,遇到恶意调用修改,则会让程序出错,或是行为变得不可测。哥建议你自己给CSHELL加个鉴权,如果CSHELL有幸被放入某个产品中去的话。