去官网下载gdb压缩包:http://ftp.gnu.org/gnu/gdb/
解压源码包,进入解压目录并配置–target=arm-linux代表程序运行目标为arm-linux
./configure --target=arm-linux
make
mkdir tmp
make install prefix=$PWD/tmp
./configure --host=arm-linux make
gdbserver 192.168.2.100:1234 ./test
arm-linux-gdb test
//输入连接命令
target remote 192.168.2.100:1234
l :查看源代码 c :运行到断点 bt :调用栈 break :打断点 step :单步运行 |
asmlinkage void sys_mycall(char *buf, int count)
{
char buf_mod[1024];
if(*buf){
copy_from_user(buf_mod, buf, (count < 1023) ? count : 1023);
buf_mod[1023] = '\0';
}else{
buf_mod[0] = '\0';
}
printk("do_mysyscall : %s\n", buf_mod);
}
CALL(sys_mycall)
asmlinkage void sys_mycall(char *buf, int count);
重新编译内核,使用新内核启动
编写应用程序
#include <errno.h>
#include <unistd.h>
void mycall(char *buf, int count)
{
/* SWI */
asm(
"mov r0, %0\n" /* save the first argument into R0 */
"mov r1, %1\n" /* save the first argument into R0 */
"swi %2\n" /* do system calls */
:/* output list */
: "r"(buf), "r"(count), "i" (0x900000 + 352)
: "r0", "r1" /* the register list who were changed */
);
}
int main(int argc, char *argv[])
{
printf("Test for mycall\n");
mycall("Powered by YellowMax\n", 21);
return 0;
}
./syscall Test for mycall do_mysyscall : Powered by YellowMax |
在printk.c中有下面一句话
__setup("console=", console_setup);
在init.h中有以下关于__setup的宏定义
#define __setup(str, fn) \
__setup_param(str, fn, fn, 0)
#define __setup_param(str, unique_id, fn, early) \
static char __setup_str_##unique_id[] __initdata = str; \
static struct obs_kernel_param __setup_##unique_id \
__attribute_used__ \
__attribute__((__section__(".init.setup"))) \
__attribute__((aligned((sizeof(long))))) \
= { __setup_str_##unique_id, fn, early }
将__setup("console=", console_setup);
代入最终就会得到
/* __initdata:#define __initdata __attribute__ ((__section__ (".init.data"))) * 代表此常量放在.init.data段,内核启动时有传入的参数的时候就会去.init.data段找相应的静态描述,以及其对应的结构体 */
static char __setup_str_console_setup[] __initdata = "console="; \
static struct obs_kernel_param __setup_console_setup \
__attribute_used__ \ //变量被启用
__attribute__((__section__(".init.setup"))) \ //.init.setup段
__attribute__((aligned((sizeof(long))))) \ //四字节对齐
= { __setup_str_console_setup, console_setup, 0 }
/* obs_kernel_param结构体:包括其对应的名字,对应的设置函数 */
struct obs_kernel_param {
const char *str;
int (*setup_func)(char *);
int early;
};
可以想象到,内核编译时会把console等等参数以及其处理函数放在一个obs_kernel_param结构体里面,此结构体被编译到.init.setup段,内核启动的时候如果有接收到来自u-boot传入的参数,就会在.init.setup段进行查找,如果有与之同名的参数时就会调用到对应的setup函数进行相关参数的设置。
static int __init console_setup(char *str)
add_preferred_console
/* 把所有控制台(不超过8个),全部添加到console_cmdline结构体数组中去 */
for(i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++)
if (strcmp(console_cmdline[i].name, name) == 0 &&
console_cmdline[i].index == idx) {
selected_console = i;
return 0;
}
register_console //在里面比较传入的console结构体里面的名字是否与console_cmdline里面的名字相同,如果相同,就把console_cmdline里面的名字,设备,驱动等传给console结构体,由printk函数来对console结构体进行调用并使用其成员,包括write函数等等。
/* console_cmdline结构体,包括:控制台名字,设备号,驱动 */
struct console_cmdline
{
char name[8]; /* Name of the driver */
int index; /* Minor dev. to use */
char *options; /* Options for the driver */
};
在printk里面定义有各个打印级别
/* printk's without a loglevel use this.. */
#define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING,默认打印级别,警告级别 */
#define MINIMUM_CONSOLE_LOGLEVEL 1 /* Minimum loglevel we let people use,最低打印级别 */
#define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything MORE serious than KERN_DEBUG,最高打印级别 */
如果级别大于等于4,也就是上面的警告级别,信息就会被打印出来,如果改动默认的打印级别就会导致更多或者更少的信息被打印
printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__); //打印出来所在的文件,所在的函数,所在的行数
__FILE__, FUNCTION, __LINE__。通过编译器实现编译的时候代入字符串常量