linux.txt

16 篇文章 0 订阅

下载内核文档
--------------
$>wget -c -r -np -k -L -p https://www.kernel.org/doc/html/v4.19/
$>wget -c -r -np -k -L -p https://www.kernel.org/doc/html/v5.4/
$>wget -c -r -np -k -L -p https://www.kernel.org/doc/html/v5.6/
$>wget -c -r -np -k -L -p https://www.kernel.org/doc/html/latest/

Linux查看执行文是否带调试信息
----------------
$>readelf -S xx-prog |grep debug
$>readelf --debug-dump xx-prog 
$>nm -a xx-prog 
$>file xx-prog 

Gdb调试过程跳出内循环
----------------
u ln.     

eg.>
1.for(...)
2.{
3.  ...
4.  for(...)
5.  {
6.    ...
7.  }
8.}

注意:此时如果执行"u 7"则会导致该函数直接执行完毕,正确做法是"u 3".

该GCC只用来编译内核
----------------
$>mkdir -p /tools/gcc
$>cp /home/vsftpd/src.tar.gz /tools/gcc
$>cd /tools/gcc && tar -xvf src.tar.gz
$>mkdir /tools/gcc/build && cd build
$>../src/configure --prefix=/tools -without-headers --with-local-prefix=/tools --with-native-system-header-dir=/tools/include --enable-obsolete --disable-libmudflap --disable-nls --disable-shared --disable-multilib --disable-decimal-float --disable-threads --disable-libatomic --disable-libgomp --disable-libmpx --disable-libquadmath --disable-libssp --disable-libvtv --disable-libstdcxx --enable-languages=c,c++

memwatch使用
----------------
$>vi xx-name.c
-------------
...
#include "memwatch.h"

void xx-name(void)   //推荐这种写法.
{
...
mwStatistics( 2 );
mwNoMansLand( MW_NML_ALL );
...
}

void yy-name(void)
{
...
mwStatistics( 2 );
mwLimit(1000000);
mwNoMansLand( MW_NML_ALL );
CHECK();
...
}

void zz-name(void)
{
...
mtrace()           //检测起点
...
muntrace();        //检测终点,检测到程序末尾时可以省略不写.
}

$>gcc -o xx-name -DMEMWATCH -DMEMWATCH_STDIO xx-name.c memwatch.c

辅助函数-打印内存数据
----------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/**
 * usage:
 * #ifdef v_debug
 * v_hexdump((char *)&variable_name, sizeof(variable_name));
 * #endif
 * 
 * @author HY (6/9/18)
 * 
 * @param v_first_address 
 * @param v_length 
 */
#ifdef v_debug
void v_hexdump(unsigned char *v_first_address, unsigned long v_length) {
    unsigned long i,j,k;
    unsigned char v_binstr[256];

    /**
     * 多行.
     */
    for ( i = 0l; i<v_length; i++ ) {
        if ( 0 == ( i%16 ) ) {                             //行首.            
            sprintf(v_binstr,"%p -",i+v_first_address);    //sprintf(v_binstr,"0x%012x -",i+v_first_address);                                   
            sprintf(v_binstr,"%s %02x",v_binstr,(unsigned char)v_first_address[i]);                  
        } 
        else if ( 15 == ( i%16 ) ) {                       //在"0x000000000000 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"后面输出字符.     
            sprintf(v_binstr,"%s %02x",v_binstr,(unsigned char)v_first_address[i]);                 
            sprintf(v_binstr,"%s  ",v_binstr);                                                               

            for ( j = i-15; j <= i; j++ ) {                                                      
                sprintf(v_binstr,"%s%c",v_binstr,('!'<v_first_address[j]&&v_first_address[j]<='~')?v_first_address[j]:'.'); 
            }
            printf("%s\n",v_binstr);                       //换行并打印字符                               
        } else {
            sprintf(v_binstr,"%s %02x",v_binstr,(unsigned char)v_first_address[i]);
        }
    }

    /*
    *单行或者最后一行.
    */
    if ( 0 != ( i%16 ) ) {
        k = 16 - ( i%16 );

        for ( j = 0; j < k; j++ ) {
            sprintf(v_binstr,"%s   ",v_binstr);
        }

        sprintf(v_binstr,"%s  ",v_binstr);
        k = 16 - k;

        for ( j = i - k; j < i; j++ ) {
            sprintf(v_binstr,"%s%c",v_binstr,('!'<v_first_address[j]&&v_first_address[j]<='~')?v_first_address[j]:'.');
        }
        printf("%s\n",v_binstr);                           //换行并打印字符
    }
}
#endif

内核辅助函数-打印内存数据
----------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/**
 * usage:
 * #ifdef v_debug
 * v_hexdump((char *)&variable_name, sizeof(variable_name));
 * #endif
 * 
 * @author HY (6/9/18)
 * 
 * @param v_first_address 
 * @param v_length 
 */
#ifdef v_debug
void v_hexdump(unsigned char *v_first_address, unsigned long v_length) {
    unsigned long i,j,k;
    unsigned char v_binstr[256];

    /**
     * 多行.
     */
    for ( i = 0l; i<v_length; i++ ) {
        if ( 0 == ( i%16 ) ) {                             //行首.            
            sprintf(v_binstr,"%p -",i+v_first_address);    //sprintf(v_binstr,"0x%012x -",i+v_first_address);                                   
            sprintf(v_binstr,"%s %02x",v_binstr,(unsigned char)v_first_address[i]);                  
        } 
        else if ( 15 == ( i%16 ) ) {                       //在"0x000000000000 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"后面输出字符.     
            sprintf(v_binstr,"%s %02x",v_binstr,(unsigned char)v_first_address[i]);                 
            sprintf(v_binstr,"%s  ",v_binstr);                                                               

            for ( j = i-15; j <= i; j++ ) {                                                      
                sprintf(v_binstr,"%s%c",v_binstr,('!'<v_first_address[j]&&v_first_address[j]<='~')?v_first_address[j]:'.'); 
            }
            printk(KERN_NOTICE "%s\n",v_binstr);                       //换行并打印字符                               
        } else {
            sprintf(v_binstr,"%s %02x",v_binstr,(unsigned char)v_first_address[i]);
        }
    }

    /*
    *单行或者最后一行.
    */
    if ( 0 != ( i%16 ) ) {
        k = 16 - ( i%16 );

        for ( j = 0; j < k; j++ ) {
            sprintf(v_binstr,"%s   ",v_binstr);
        }

        sprintf(v_binstr,"%s  ",v_binstr);
        k = 16 - k;

        for ( j = i - k; j < i; j++ ) {
            sprintf(v_binstr,"%s%c",v_binstr,('!'<v_first_address[j]&&v_first_address[j]<='~')?v_first_address[j]:'.');
        }
        printk(KERN_NOTICE "%s\n",v_binstr);                           //换行并打印字符
    }
}
#endif

内核中循环打印一串字符的例子
----------------
$>cd linux-x.y.z
$>vi mykernel/Makefile
-------------
#
# Makefile for the linux mykernel.
#

obj-y     = mymain.o myinterrupt.o

$>vi mykernel/myinterrupt.c
-------------
/*
 *  linux/mykernel/myinterrupt.c
 *
 *  Kernel internal my_timer_handler
 *
 *  Copyright (C) 2013  Mengning
 *
 */
#include <linux/kernel_stat.h>
#include <linux/export.h>
#include <linux/interrupt.h>
#include <linux/percpu.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/swap.h>
#include <linux/pid_namespace.h>
#include <linux/notifier.h>
#include <linux/thread_info.h>
#include <linux/time.h>
#include <linux/jiffies.h>
#include <linux/posix-timers.h>
#include <linux/cpu.h>
#include <linux/syscalls.h>
#include <linux/delay.h>
#include <linux/tick.h>
#include <linux/kallsyms.h>
#include <linux/irq_work.h>
#include <linux/sched.h>
#include <linux/sched/sysctl.h>
#include <linux/slab.h>

#include <asm/uaccess.h>
#include <asm/unistd.h>
#include <asm/div64.h>
#include <asm/timex.h>
#include <asm/io.h>

#define CREATE_TRACE_POINTS
#include <trace/events/timer.h>

/*
 * Called by timer interrupt.
 */
void my_timer_handler(void)
{
    printk(KERN_NOTICE "\n>>>>>>>>>>>>>>>>>my_timer_handler here<<<<<<<<<<<<<<<<<<\n\n");
}

$>vi mykernel/mymain.c
-------------
/*
 *  linux/mykernel/mymain.c
 *
 *  Kernel internal my_start_kernel
 *
 *  Copyright (C) 2013  Mengning
 *
 */
#include <linux/types.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/kernel.h>
#include <linux/syscalls.h>
#include <linux/stackprotector.h>
#include <linux/string.h>
#include <linux/ctype.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/initrd.h>
#include <linux/bootmem.h>
#include <linux/acpi.h>
#include <linux/tty.h>
#include <linux/percpu.h>
#include <linux/kmod.h>
#include <linux/vmalloc.h>
#include <linux/kernel_stat.h>
#include <linux/start_kernel.h>
#include <linux/security.h>
#include <linux/smp.h>
#include <linux/profile.h>
#include <linux/rcupdate.h>
#include <linux/moduleparam.h>
#include <linux/kallsyms.h>
#include <linux/writeback.h>
#include <linux/cpu.h>
#include <linux/cpuset.h>
#include <linux/cgroup.h>
#include <linux/efi.h>
#include <linux/tick.h>
#include <linux/interrupt.h>
#include <linux/taskstats_kern.h>
#include <linux/delayacct.h>
#include <linux/unistd.h>
#include <linux/rmap.h>
#include <linux/mempolicy.h>
#include <linux/key.h>
#include <linux/buffer_head.h>
#include <linux/page_cgroup.h>
#include <linux/debug_locks.h>
#include <linux/debugobjects.h>
#include <linux/lockdep.h>
#include <linux/kmemleak.h>
#include <linux/pid_namespace.h>
#include <linux/device.h>
#include <linux/kthread.h>
#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/idr.h>
#include <linux/kgdb.h>
#include <linux/ftrace.h>
#include <linux/async.h>
#include <linux/kmemcheck.h>
#include <linux/sfi.h>
#include <linux/shmem_fs.h>
#include <linux/slab.h>
#include <linux/perf_event.h>
#include <linux/file.h>
#include <linux/ptrace.h>
#include <linux/blkdev.h>
#include <linux/elevator.h>

#include <asm/io.h>
#include <asm/bugs.h>
#include <asm/setup.h>
#include <asm/sections.h>
#include <asm/cacheflush.h>

#ifdef CONFIG_X86_LOCAL_APIC
#include <asm/smp.h>
#endif

void __init my_start_kernel(void)
{
    int i = 0;
    while(1)
    {
        i++;
        if(i%100000 == 0)
            printk(KERN_NOTICE "my_start_kernel here  %d \n",i);
            
    }
}

$>vi mykernel/README.md
-------------
mykernel
==========
It is a platform to write your own OS kernel,its based on Linux Kernel x.y.z source code.

$>vi arch/x86/kernel/time.c
-------------
...
#include <linux/time.h>
#include <linux/timer.h>                            /*add by self.*/
#include <linux/export.h>
...
static irqreturn_t timer_interrupt(int irq, void *dev_id)
{
    global_clock_event->event_handler(global_clock_event);
    my_timer_handler();                             /*add by self.*/
    return IRQ_HANDLED;
}
...
void __init setup_default_timer_irq(void)
{
    printk(KERN_NOTICE "timer interrupt setup\n");  /*add by self.*/
    setup_irq(0, &irq0);
}
...

$>vi include/linux/start_kernel.h
-------------
...
extern asmlinkage void __init start_kernel(void);
extern void __init my_start_kernel(void);          /*add by self.*/
...

$>vi include/linux/timer.h
-------------
...
extern void init_timers(void);
extern void run_local_timers(void);
extern void my_timer_handler(void);               /*add by self.*/
...

$>vi init/main.c
-------------
...
asmlinkage void __init start_kernel(void)
{
   ...
   my_start_kernel();                            /*add by self.*/
   ...
}
...

$>vi Makefile
-------------
...
core-y        += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ mykernel/
...

注意:"mykernel/"自定义内核源码目录.

$>vi mykernel/myinterrupt.c                    /*version 2*/
-------------
/*
 *  linux/mykernel/myinterrupt.c
 *
 *  Kernel internal my_timer_handler
 *
 *  Copyright (C) 2013  Mengning
 *
 */
#include <linux/types.h>
#include <linux/string.h>
#include <linux/ctype.h>
#include <linux/tty.h>
#include <linux/vmalloc.h>

#include "mypcb.h"

extern tPCB task[MAX_TASK_NUM];
extern tPCB * my_current_task;
extern volatile int my_need_sched;
volatile int time_count = 0;

/*
 * Called by timer interrupt.
 * it runs in the name of current running process,
 * so it use kernel stack of current running process
 */
void my_timer_handler(void)
{
#if 1
    if(time_count%1000 == 0 && my_need_sched != 1)
    {
        printk(KERN_NOTICE ">>>my_timer_handler here<<<\n");
        my_need_sched = 1;
    } 
    time_count ++ ;  
#endif
    return;      
}

void my_schedule(void)
{
    tPCB * next;
    tPCB * prev;

    if(my_current_task == NULL 
        || my_current_task->next == NULL)
    {
        return;
    }
    printk(KERN_NOTICE ">>>my_schedule<<<\n");
    /* schedule */
    next = my_current_task->next;
    prev = my_current_task;
    if(next->state == 0)/* -1 unrunnable, 0 runnable, >0 stopped */
    {
        my_current_task = next; 
        printk(KERN_NOTICE ">>>switch %d to %d<<<\n",prev->pid,next->pid);  
        /* switch to next process */
        asm volatile(    
            "pushl %%ebp\n\t"         /* save ebp */
            "movl %%esp,%0\n\t"     /* save esp */
            "movl %2,%%esp\n\t"     /* restore  esp */
            "movl $1f,%1\n\t"       /* save eip */    
            "pushl %3\n\t" 
            "ret\n\t"                 /* restore  eip */
            "1:\t"                  /* next process start here */
            "popl %%ebp\n\t"
            : "=m" (prev->thread.sp),"=m" (prev->thread.ip)
            : "m" (next->thread.sp),"m" (next->thread.ip)
        ); 
     
    }
    else
    {
        next->state = 0;
        my_current_task = next;
        printk(KERN_NOTICE ">>>switch %d to %d<<<\n",prev->pid,next->pid);
        /* switch to new process */
        asm volatile(    
            "pushl %%ebp\n\t"         /* save ebp */
            "movl %%esp,%0\n\t"     /* save esp */
            "movl %2,%%esp\n\t"     /* restore  esp */
            "movl %2,%%ebp\n\t"     /* restore  ebp */
            "movl $1f,%1\n\t"       /* save eip */    
            "pushl %3\n\t" 
            "ret\n\t"                 /* restore  eip */
            : "=m" (prev->thread.sp),"=m" (prev->thread.ip)
            : "m" (next->thread.sp),"m" (next->thread.ip)
        );          
    }   
    return;    
}

$>vi mykernel/mymain.c                         /*version 2*/
-------------
/*
 *  linux/mykernel/mymain.c
 *
 *  Kernel internal my_start_kernel
 *
 *  Copyright (C) 2013  Mengning
 *
 */
#include <linux/types.h>
#include <linux/string.h>
#include <linux/ctype.h>
#include <linux/tty.h>
#include <linux/vmalloc.h>

#include "mypcb.h"

tPCB task[MAX_TASK_NUM];
tPCB * my_current_task = NULL;
volatile int my_need_sched = 0;

void my_process(void);

void __init my_start_kernel(void)
{
    int pid = 0;
    int i;
    /* Initialize process 0*/
    task[pid].pid = pid;
    task[pid].state = 0;/* -1 unrunnable, 0 runnable, >0 stopped */
    task[pid].task_entry = task[pid].thread.ip = (unsigned long)my_process;
    task[pid].thread.sp = (unsigned long)&task[pid].stack[KERNEL_STACK_SIZE-1];
    task[pid].next = &task[pid];
    /*fork more process */
    for(i=1;i<MAX_TASK_NUM;i++)
    {
        memcpy(&task[i],&task[0],sizeof(tPCB));
        task[i].pid = i;
        task[i].state = -1;
        task[i].thread.sp = (unsigned long)&task[i].stack[KERNEL_STACK_SIZE-1];
        task[i].next = task[i-1].next;
        task[i-1].next = &task[i];
    }
    /* start process 0 by task[0] */
    pid = 0;
    my_current_task = &task[pid];
    asm volatile(
        "movl %1,%%esp\n\t"     /* set task[pid].thread.sp to esp */
        "pushl %1\n\t"             /* push ebp */
        "pushl %0\n\t"             /* push task[pid].thread.ip */
        "ret\n\t"                 /* pop task[pid].thread.ip to eip */
        "popl %%ebp\n\t"
        : 
        : "c" (task[pid].thread.ip),"d" (task[pid].thread.sp)    /* input c or d mean %ecx/%edx*/
    );
}   
void my_process(void)
{
    int i = 0;
    while(1)
    {
        i++;
        if(i%10000000 == 0)
        {
            printk(KERN_NOTICE "this is process %d -\n",my_current_task->pid);
            if(my_need_sched == 1)
            {
                my_need_sched = 0;
                my_schedule();
            }
            printk(KERN_NOTICE "this is process %d +\n",my_current_task->pid);
        }     
    }
}

$>vi mypcb.h                                   /*version 2*/
-------------
/*
 *  linux/mykernel/mypcb.h
 *
 *  Kernel internal PCB types
 *
 *  Copyright (C) 2013  Mengning
 *
 */

#define MAX_TASK_NUM        4
#define KERNEL_STACK_SIZE   1024*8

/* CPU-specific state of this task */
struct Thread {
    unsigned long        ip;
    unsigned long        sp;
};

typedef struct PCB{
    int pid;
    volatile long state;    /* -1 unrunnable, 0 runnable, >0 stopped */
    char stack[KERNEL_STACK_SIZE];
    /* CPU-specific state of this task */
    struct Thread thread;
    unsigned long    task_entry;
    struct PCB *next;
}tPCB;

void my_schedule(void);

$>vi Makefile                                  /*version 2*/
-------------
#
# Makefile for the linux mykernel.
#

obj-y     = mymain.o myinterrupt.o

$>vi mykernel/myinterrupt.c                    /*version 3*/
-------------
/*    mykernel--Simple simulation of the linux OS  process schedule
 *
 *  linux/mykernel/myinterrupt.c
 *
 *  Kernel internal my_timer_handler
 *
 *  Copyright (C) 2013  Mengning
 *  
 *  Modified 2014 zhyq
 * 
 * 
 *  You can redistribute or modify this program under the terms
 *  of the GNU General Public License as published by
 *  the Free Software Foundation.
 *
 * You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include <linux/kernel_stat.h>
#include <linux/export.h>
#include <linux/interrupt.h>
#include <linux/percpu.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/swap.h>
#include <linux/pid_namespace.h>
#include <linux/notifier.h>
#include <linux/thread_info.h>
#include <linux/time.h>
#include <linux/jiffies.h>
#include <linux/posix-timers.h>
#include <linux/cpu.h>
#include <linux/syscalls.h>
#include <linux/delay.h>
#include <linux/tick.h>
#include <linux/kallsyms.h>
#include <linux/irq_work.h>
#include <linux/sched.h>
#include <linux/sched/sysctl.h>
#include <linux/slab.h>

#include <asm/uaccess.h>
#include <asm/unistd.h>
#include <asm/div64.h>
#include <asm/timex.h>
#include <asm/io.h>

#include <linux/types.h>
#include <linux/string.h>
#include <linux/ctype.h>
#include <linux/tty.h>
#include <linux/vmalloc.h>

#include "mypcb.h"

#define CREATE_TRACE_POINTS
#include <trace/events/timer.h>

extern tPCB task[MAX_TASK_NUM];
extern tPCB * my_current_task;
extern volatile int my_need_sched;
volatile int time_count = 0;

/*
* Called by timer interrupt.
* it runs in the name of current running process,
* so it use kernel stack of current running process
*/
void my_timer_handler(void)
{
#if 1
    // make sure need schedule after system circle 2000 times.
    if(time_count%2000 == 0 && my_need_sched != 1)
    {
        my_need_sched = 1;
    //time_count=0;
    }
    time_count ++ ;
#endif
    return;
}

void all_task_print(void);

tPCB * get_next(void)
{
    int pid,i;
    tPCB * point=NULL;
    tPCB * hig_pri=NULL;//points to the the hightest task
    all_task_print();
    hig_pri=my_current_task;
    for(i=0;i<MAX_TASK_NUM;i++)
        if(task[i].priority<hig_pri->priority)    
            hig_pri=&task[i];
    printk("                higst process is:%d priority is:%d\n",hig_pri->pid,hig_pri->priority);
    return hig_pri;

}//end of priority_schedule

void my_schedule(void)
{
    tPCB * next;
    tPCB * prev;
    // if there no task running or only a task ,it shouldn't need schedule
    if(my_current_task == NULL
        || my_current_task->next == NULL)
    {
    printk(KERN_NOTICE "                time out!!!,but no more than 2 task,need not schedule\n");
     return;
    }
    /* schedule */

    next = get_next();
    prev = my_current_task;
    printk(KERN_NOTICE "                the next task is %d priority is %u\n",next->pid,next->priority);
    if(next->state == 0)/* -1 unrunnable, 0 runnable, >0 stopped */
    {//save current scene
     /* switch to next process */
     asm volatile(    
         "pushl %%ebp\n\t" /* save ebp */
         "movl %%esp,%0\n\t" /* save esp */
         "movl %2,%%esp\n\t" /* restore esp */
         "movl $1f,%1\n\t" /* save eip */    
         "pushl %3\n\t"
         "ret\n\t" /* restore eip */
         "1:\t" /* next process start here */
         "popl %%ebp\n\t"
         : "=m" (prev->thread.sp),"=m" (prev->thread.ip)
         : "m" (next->thread.sp),"m" (next->thread.ip)
     );
     my_current_task = next;//switch to the next task
     printk(KERN_NOTICE "                switch from %d process to %d process\n                >>>process %d running!!!<<<\n\n",prev->pid,next->pid,next->pid);

  }
    else
    {
        next->state = 0;
        my_current_task = next;
    printk(KERN_NOTICE "                switch from %d process to %d process\n                >>>process %d running!!!<<<\n\n\n",prev->pid,next->pid,next->pid);

     /* switch to new process */
     asm volatile(    
         "pushl %%ebp\n\t" /* save ebp */
         "movl %%esp,%0\n\t" /* save esp */
         "movl %2,%%esp\n\t" /* restore esp */
         "movl %2,%%ebp\n\t" /* restore ebp */
         "movl $1f,%1\n\t" /* save eip */    
         "pushl %3\n\t"
         "ret\n\t" /* restore eip */
         : "=m" (prev->thread.sp),"=m" (prev->thread.ip)
         : "m" (next->thread.sp),"m" (next->thread.ip)
     );
    }
    return;    
}//end of my_schedule

void all_task_print(void)
{
    int i,cnum=62;//
    printk(KERN_NOTICE "\n                current task is:%d   all task in OS are:\n",my_current_task->pid);

    printk("        ");
    for(i=0;i<cnum;i++)
        printk("-");
    printk("\n        |  process:");
    for(i=0;i< MAX_TASK_NUM;i++)
        printk("| %2d ",i);
    printk("|\n        | priority:");
    for(i=0;i<MAX_TASK_NUM;i++)
        printk("| %2d ",task[i].priority);

    printk("|\n        ");
    for(i=0;i<cnum;i++)
        printk("-");
    printk("\n");
}

$>vi mykernel/mymain.c                         /*version 3*/
-------------
/*    mykernel--Simple simulation of the linux OS  process schedule
 *
 *  linux/mykernel/mymain.c
 *
 *  Kernel internal my_timer_handler
 *
 *  Copyright (C) 2013  Mengning
 *  
 *  Modified zhyq
 * 
 * 
 *  You can redistribute or modify this program under the terms
 *  of the GNU General Public License as published by
 *  the Free Software Foundation.
 *
 * You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include <linux/types.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/kernel.h>
#include <linux/syscalls.h>
#include <linux/stackprotector.h>
#include <linux/string.h>
#include <linux/ctype.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/initrd.h>
#include <linux/bootmem.h>
#include <linux/acpi.h>
#include <linux/tty.h>
#include <linux/percpu.h>
#include <linux/kmod.h>
#include <linux/vmalloc.h>
#include <linux/kernel_stat.h>
#include <linux/start_kernel.h>
#include <linux/security.h>
#include <linux/smp.h>
#include <linux/profile.h>
#include <linux/rcupdate.h>
#include <linux/moduleparam.h>
#include <linux/kallsyms.h>
#include <linux/writeback.h>
#include <linux/cpu.h>
#include <linux/cpuset.h>
#include <linux/cgroup.h>
#include <linux/efi.h>
#include <linux/tick.h>
#include <linux/interrupt.h>
#include <linux/taskstats_kern.h>
#include <linux/delayacct.h>
#include <linux/unistd.h>
#include <linux/rmap.h>
#include <linux/mempolicy.h>
#include <linux/key.h>
#include <linux/buffer_head.h>
#include <linux/page_cgroup.h>
#include <linux/debug_locks.h>
#include <linux/debugobjects.h>
#include <linux/lockdep.h>
#include <linux/kmemleak.h>
#include <linux/pid_namespace.h>
#include <linux/device.h>
#include <linux/kthread.h>
#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/idr.h>
#include <linux/kgdb.h>
#include <linux/ftrace.h>
#include <linux/async.h>
#include <linux/kmemcheck.h>
#include <linux/sfi.h>
#include <linux/shmem_fs.h>
#include <linux/slab.h>
#include <linux/perf_event.h>
#include <linux/file.h>
#include <linux/ptrace.h>
#include <linux/blkdev.h>
#include <linux/elevator.h>

#include <asm/io.h>
#include <asm/bugs.h>
#include <asm/setup.h>
#include <asm/sections.h>
#include <asm/cacheflush.h>

#include <linux/vmalloc.h>

#include <linux/module.h> 
#include <linux/kernel.h>

#ifdef CONFIG_X86_LOCAL_APIC
#include <asm/smp.h>
#endif
#include "mypcb.h"

tPCB task[MAX_TASK_NUM];
tPCB * my_current_task = NULL;
volatile int my_need_sched = 0;

void my_process(void);
unsigned long get_rand(int );

void sand_priority(void)
{
    int i;
    for(i=0;i<MAX_TASK_NUM;i++)
        task[i].priority=get_rand(PRIORITY_MAX);
}
void __init my_start_kernel(void)
{
    int pid = 0;
    /* Initialize process 0*/
    task[pid].pid = pid;
    task[pid].state = 0;/* -1 unrunnable, 0 runnable, >0 stopped */
    // set task 0 execute entry address to my_process
    task[pid].task_entry = task[pid].thread.ip = (unsigned long)my_process;
    task[pid].thread.sp = (unsigned long)&task[pid].stack[KERNEL_STACK_SIZE-1];
    task[pid].next = &task[pid];
    /*fork more process */
    for(pid=1;pid<MAX_TASK_NUM;pid++)
    {
        memcpy(&task[pid],&task[0],sizeof(tPCB));
        task[pid].pid = pid;
        task[pid].state = -1;
        task[pid].thread.sp = (unsigned long)&task[pid].stack[KERNEL_STACK_SIZE-1];
    task[pid].priority=get_rand(PRIORITY_MAX);//each time all tasks get a random priority
    }
    task[MAX_TASK_NUM-1].next=&task[0];
    printk(KERN_NOTICE "\n\n\n\n\n\n                system begin :>>>process 0 running!!!<<<\n\n");
    /* start process 0 by task[0] */
    pid = 0;
    my_current_task = &task[pid];
asm volatile(
     "movl %1,%%esp\n\t" /* set task[pid].thread.sp to esp */
     "pushl %1\n\t" /* push ebp */
     "pushl %0\n\t" /* push task[pid].thread.ip */
     "ret\n\t" /* pop task[pid].thread.ip to eip */
     "popl %%ebp\n\t"
     :
     : "c" (task[pid].thread.ip),"d" (task[pid].thread.sp)    /* input c or d mean %ecx/%edx*/
);
}
void my_process(void)
{
    int i = 0;
    while(1)
    {
        i++;
        if(i%10000000 == 0)
        {
      
            if(my_need_sched == 1)
            {
                my_need_sched = 0;
        sand_priority();
           my_schedule();  
        
       }
        }
    }
}//end of my_process

//produce a random priority to a task
unsigned long get_rand(max)
{
    unsigned long a;
    unsigned long umax;
    umax=(unsigned long)max;
     get_random_bytes(&a, sizeof(unsigned long ));
    a=(a+umax)%umax;
    return a;
}

$>vi mypcb.h                                   /*version 3*/
-------------
/*    mykernel--Simple simulation of the linux OS  process schedule
 *
 *  linux/mykernel/mypcb.h
 *
 *  Kernel internal my_timer_handler
 *
 *  Copyright (C) 2013  Mengning
 *  
 *  Modified 2014 Yunquan Zhang  <zhangyunquan@hotmail.com>
 * 
 * 
 *  You can redistribute or modify this program under the terms
 *  of the GNU General Public License as published by
 *  the Free Software Foundation.
 *
 * You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#define MAX_TASK_NUM 10 // max num of task in system
#define KERNEL_STACK_SIZE 1024*8
#define PRIORITY_MAX 30 //priority range from 0 to 30

/* CPU-specific state of this task */
struct Thread {
    unsigned long    ip;//point to cpu run address
    unsigned long    sp;//point to the thread stack's top address
    //todo add other attrubte of system thread
};
//PCB Struct
typedef struct PCB{
    int pid; // pcb id 
    volatile long state;    /* -1 unrunnable, 0 runnable, >0 stopped */
    char stack[KERNEL_STACK_SIZE];// each pcb stack size is 1024*8
    /* CPU-specific state of this task */
    struct Thread thread;
    unsigned long    task_entry;//the task execute entry memory address
    struct PCB *next;//pcb is a circular linked list
    unsigned long priority;// task priority
    //todo add other attrubte of process control block
}tPCB;

//void my_schedule(int pid);
void my_schedule(void);

$>vi Makefile                                  /*version 3*/
-------------
#
# Makefile for the linux mykernel.
#

obj-y     = mymain.o myinterrupt.o

系统调用列表
----------------
$>vi linux-x.y.z/arch/x86/syscalls/syscall_32.tbl
$>vi linux-x.y.z/arch/x86/syscalls/syscall_64.tbl

注意:使用库函数api和c代码中嵌入汇编代码两种方式使用同一个系统调用.

例子编译与运行
----------------
$>make allnoconfig                                                 #最小编译(最简内核配置).
$>make                                                             #编译
$>/usr/bin/qemu-system-x86_64 -kernel arch/x86/boot/bzImage        #使用x86_64模式启动内核.
$>/usr/bin/qemu-system-x86_64 -no-frame -enable-kvm -kernel arch/x86/boot/bzImage
$>/usr/bin/qemu-system-x86_64 -curses -kernel arch/x86/boot/bzImage
or
$>/usr/bin/qemu-system-i386 -kernel arch/x86/boot/bzImage          #使用i386模式启动内核.
$>/usr/bin/qemu-system-i386 -no-frame -enable-kvm -kernel arch/x86/boot/bzImage
$>/usr/bin/qemu-system-i386 -curses -kernel arch/x86/boot/bzImage
$>diff -Naur linux-x.y.z linux-x.y.z.new/ > linux-x.y.z_xx.patch   #创建补丁.
$>cd linux-x.y.z && patch -p1 < /path/linux-x.y.z_xx.patch         #给内核打补丁.

注意:在qemu中ctrl+alt退出鼠标光标,修改内核"linux-x.y.z/Makfile"会在编译的时候生效.

学习内核汇编
----------------
$>gcc -S -o xx.s xx.c -m32        

注意:通过反汇编简单的c程序来学习汇编.

编译内核
----------------
$>make allyesconfig          #尽可能多编译yes选项.
$>make allnoconfig           #最小编译(最简内核配置).
$>make allmodconfig          #编译所有模块.
$>make randconfig            #使用的是Kconfig.
$>make oldconfig             

调试x86最简单的内核
---------------
$>make allnoconfig           #step.1
$>make menuconfig            #step.2,并进行"Kernel hacking  --->"设置;最后根据"调试内核必须的选项"检查是否都设置了.

注意:根据实际操作已经证明可行了.

调试内核必须的选项
----------------
CONFIG_DEBUG_INFO=y
CONFIG_FRAME_POINTER=y
CONFIG_DEBUG_KERNEL=y
CONFIG_DEBUG_FS=y
CONFIG_SLUB_DEBUG_ON=y
CONFIG_DMA_API_DEBUG=y

编译指定架构的内核
----------------
$>make x86_64_defconfig           #生成x86_64(.config)配置文件,然后make即可编译内核.
$>make i386_defconfig             #生成x86(.config)配置文件,然后make即可编译内核.

调试x86_64内核
----------------
$>make x86_64_defconfig    #step.1
$>make menuconfig          #step.2,并进行"Kernel hacking  --->"设置;最后根据"调试内核必须的选项"检查是否都设置了.

调试x86内核
----------------
$>make i386_defconfig      #step.1
$>make menuconfig          #step.2,并进行"Kernel hacking  --->"设置;最后根据"调试内核必须的选项"检查是否都设置了.

交叉编译嵌入式内核
----------------
$>make ARCH=arm CROSS_COMPILE=arm-linux-gnu- allnoconfig                    #step.1,"CROSS_COMPILE"设置编译器的前缀.
$>make ARCH=arm CROSS_COMPILE=arm-linux-gnu-                                #step.2,编译内核.
$>make ARCH=arm CROSS_COMPILE=arm-linux-gnu- modules                        #step.3,编译模块.
$>make ARCH=arm CROSS_COMPILE=arm-linux-gnu- modules_install                #step.4,模块安装.
$>mkinitramfs ARCH=arm CROSS_COMPILE=arm-linux-gnu- -o initrd.img-<x.y.z>   #step.5,创建内存文件.
$>update-grub                                                               #step.6
$>reboot                                                                    #step.7

eg.
$>make ARCH=x86 allnoconfig                                        #step.1
$>make ARCH=x86                                                    #step.2

$>make ARCH=x86_64 allnoconfig                                     #step.1
$>make ARCH=x86_64                                                 #step.2

$>make ARCH=x86_64 CROSS_COMPILE=x86_64-linux-gnu- allnoconfig     #step.1
$>make ARCH=x86_64 CROSS_COMPILE=x86_64-linux-gnu-                 #step.2
$>make ARCH=x86_64 CROSS_COMPILE=x86_64-linux-gnu- modules
$>mkinitramfs ARCH=x86_64 CROSS_COMPILE=x86_64-linux-gnu- -o initrd.img-<x.y.z>
$>update-grub 
$>reboot   

$>make ARCH=arm allnoconfig                                        #step.1
$>make ARCH=arm                                                    #step.2  

修改内核编译优化选项
----------------
$>vi linux-x.y.z/Makefile
-------------
...
HOSTCFLAGS   = -Wall -Wmissing-prototypes -Wstrict-prototypes -O0 -fomit-frame-pointer
HOSTCXXFLAGS = -O0
#或者使用下面配置观察详细的编译过程
HOSTCFLAGS   = -v -g -Wall -Wmissing-prototypes -Wstrict-prototypes -O0 -fomit-frame-pointer
HOSTCXXFLAGS = -v -g -O0
...

...
all: vmlinux

ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
KBUILD_CFLAGS    += -O1
else
KBUILD_CFLAGS    += -O1
endif
...

内核入口函数
----------------
$>vi linux-x.y.z/init/main.c
-------------
...
asmlinkage void __init start_kernel(void)
{
...
}
...

生成内核帮助文档
----------------
$>make htmldocs

内核调试
----------------
$>/usr/bin/qemu-system-x86_64 -no-quit -S -s -kernel /path/linux-x.y.z/arch/x86/boot/bzImage      #启动一个新的终端执行当前命令.
$>cd /path/linux-x.y.z && gdb vmlinux                                                             #在当前终端中执行命令.
gdb$>target remote 127.0.0.1:1234
gdb$>b start_kernel                                                                               #将断点打在start_kernel.
gdb$>b ...                                                                                        #打断点.
gdb$>set args ...                                                                                 #设置运行参数.
gdb$>c or s                                                                                       #继续(continue)运行.
gdb$>bt                                                                                           #查看堆栈.

内核调试脚本
----------------
$>mkdir /path/bin
$>vi ~/.bashrc
-------------
export PATH=$PATH:/path/bin

$>vi /path/bin/kterminal.sh                                   #step.1
-------------
#!/bin/bash

KDIR=/path/linux-x.y.z
#####打开一个终端,一个qemu窗口#####
cd $KDIR && gnome-terminal --hide-menubar  --title="Terminal" --geometry=100X85+85+85 &
/usr/bin/qemu-system-x86_64 -no-quit -S -s -kernel $KDIR/arch/x86/boot/bzImage 

$>vi /path/bin/r.sh                                          #step.2
-------------
#!/bin/bash

/usr/bin/qemu-system-x86_64 -no-quit -S -s -kernel /path/linux-x.y.z/arch/x86/boot/bzImage 

$>vi /path/bin/kdebug.sh                                     #step.3
-------------
#!/bin/bash

#####启动gdb的shell脚本文件#####
mkdir -p /path/debug
touch /path/debug/khistory
touch /path/debug/kcfg
touch /path/debug/log.txt
touch /path/debug/breakpoints

gdb -x /path/debug/kcfg /path/linux-x.y.z/vmlinux           #注意这里必须使用绝对路径.

$>vi /path/debug/kcfg
-------------
#####gdb配置文件#####
set confirm off
set pagination off
set print elements 0
set print array-indexes on
set print pretty on
set history filename /path/debug/khistory                   #注意这里必须使用绝对路径.
set history save on
set logging file /path/debug/log.txt                        #注意这里必须使用绝对路径.
set logging on
set logging overwrite on

source /path/debug/breakpoints                              #注意这里必须使用绝对路径.
python sys.path.append("/usr/share/gcc-4.7/python/");
target remote 127.0.0.1:1234

#breakpoints
b start_kernel
display $pc
display /x $cs

define rr
  target remote 127.0.0.1:1234
  c
end

define xx-cmd                                                #自定义命令.
  ...
  yy-context
  ...
end

$>kdebug.sh                                                  #step.4

构建init进程
----------------
vi linktable.c
-------------
#include<stdio.h>
#include<stdlib.h>
#include <pthread.h>
#include"linktable.h"

/*
 * LinkTable Type
 */
struct LinkTable
{
    tLinkTableNode *pHead;
    tLinkTableNode *pTail;
    int            SumOfNode;
    pthread_mutex_t mutex;

};


/*
 * Create a LinkTable
 */
tLinkTable * CreateLinkTable()
{
    tLinkTable * pLinkTable = (tLinkTable *)malloc(sizeof(tLinkTable));
    if(pLinkTable == NULL)
    {
        return NULL;
    }
    pLinkTable->pHead = NULL;
    pLinkTable->pTail = NULL;
    pLinkTable->SumOfNode = 0;
    pthread_mutex_init(&(pLinkTable->mutex), NULL);
    return pLinkTable;
}

/*
 * Delete a LinkTable
 */
int DeleteLinkTable(tLinkTable *pLinkTable)
{
    if(pLinkTable == NULL)
    {
        return FAILURE;
    }
    while(pLinkTable->pHead != NULL)
    {
        tLinkTableNode * p = pLinkTable->pHead;
        pthread_mutex_lock(&(pLinkTable->mutex));
        pLinkTable->pHead = pLinkTable->pHead->pNext;
        pLinkTable->SumOfNode -= 1 ;
        pthread_mutex_unlock(&(pLinkTable->mutex));
        free(p);
    }
    pLinkTable->pHead = NULL;
    pLinkTable->pTail = NULL;
    pLinkTable->SumOfNode = 0;
    pthread_mutex_destroy(&(pLinkTable->mutex));
    free(pLinkTable);
    return SUCCESS;        
}

/*
 * Add a LinkTableNode to LinkTable
 */
int AddLinkTableNode(tLinkTable *pLinkTable,tLinkTableNode * pNode)
{
    if(pLinkTable == NULL || pNode == NULL)
    {
        return FAILURE;
    }
    pNode->pNext = NULL;
    pthread_mutex_lock(&(pLinkTable->mutex));
    if(pLinkTable->pHead == NULL)
    {
        pLinkTable->pHead = pNode;
    }
    if(pLinkTable->pTail == NULL)
    {
        pLinkTable->pTail = pNode;
    }
    else
    {
        pLinkTable->pTail->pNext = pNode;
        pLinkTable->pTail = pNode;
    }
    pLinkTable->SumOfNode += 1 ;
    pthread_mutex_unlock(&(pLinkTable->mutex));
    return SUCCESS;        
}

/*
 * Delete a LinkTableNode from LinkTable
 */
int DelLinkTableNode(tLinkTable *pLinkTable,tLinkTableNode * pNode)
{
    if(pLinkTable == NULL || pNode == NULL)
    {
        return FAILURE;
    }
    pthread_mutex_lock(&(pLinkTable->mutex));
    if(pLinkTable->pHead == pNode)
    {
        pLinkTable->pHead = pLinkTable->pHead->pNext;
        pLinkTable->SumOfNode -= 1 ;
        if(pLinkTable->SumOfNode == 0)
        {
            pLinkTable->pTail = NULL;    
        }
        pthread_mutex_unlock(&(pLinkTable->mutex));
        return SUCCESS;
    }
    tLinkTableNode * pTempNode = pLinkTable->pHead;
    while(pTempNode != NULL)
    {    
        if(pTempNode->pNext == pNode)
        {
            pTempNode->pNext = pTempNode->pNext->pNext;
            pLinkTable->SumOfNode -= 1 ;
            if(pLinkTable->SumOfNode == 0)
            {
                pLinkTable->pTail = NULL;    
            }
            pthread_mutex_unlock(&(pLinkTable->mutex));
            return SUCCESS;                    
        }
        pTempNode = pTempNode->pNext;
    }
    pthread_mutex_unlock(&(pLinkTable->mutex));
    return FAILURE;        
}

/*
 * Search a LinkTableNode from LinkTable
 * int Conditon(tLinkTableNode * pNode);
 */
tLinkTableNode * SearchLinkTableNode(tLinkTable *pLinkTable, int Conditon(tLinkTableNode * pNode, void * args), void * args)
{
    if(pLinkTable == NULL || Conditon == NULL)
    {
        return NULL;
    }
    tLinkTableNode * pNode = pLinkTable->pHead;
    while(pNode != NULL)
    {    
        if(Conditon(pNode,args) == SUCCESS)
        {
            return pNode;                    
        }
        pNode = pNode->pNext;
    }
    return NULL;
}

/*
 * get LinkTableHead
 */
tLinkTableNode * GetLinkTableHead(tLinkTable *pLinkTable)
{
    if(pLinkTable == NULL)
    {
        return NULL;
    }    
    return pLinkTable->pHead;
}

/*
 * get next LinkTableNode
 */
tLinkTableNode * GetNextLinkTableNode(tLinkTable *pLinkTable,tLinkTableNode * pNode)
{
    if(pLinkTable == NULL || pNode == NULL)
    {
        return NULL;
    }
    tLinkTableNode * pTempNode = pLinkTable->pHead;
    while(pTempNode != NULL)
    {    
        if(pTempNode == pNode)
        {
            return pTempNode->pNext;                    
        }
        pTempNode = pTempNode->pNext;
    }
    return NULL;
}

$>vi linktable.h
-------------
#ifndef _LINK_TABLE_H_
#define _LINK_TABLE_H_

#include <pthread.h>

#define SUCCESS 0
#define FAILURE (-1)

/*
 * LinkTable Node Type
 */
typedef struct LinkTableNode
{
    struct LinkTableNode * pNext;
}tLinkTableNode;

/*
 * LinkTable Type
 */
typedef struct LinkTable tLinkTable;

/*
 * Create a LinkTable
 */
tLinkTable * CreateLinkTable();
/*
 * Delete a LinkTable
 */
int DeleteLinkTable(tLinkTable *pLinkTable);
/*
 * Add a LinkTableNode to LinkTable
 */
int AddLinkTableNode(tLinkTable *pLinkTable,tLinkTableNode * pNode);
/*
 * Delete a LinkTableNode from LinkTable
 */
int DelLinkTableNode(tLinkTable *pLinkTable,tLinkTableNode * pNode);
/*
 * Search a LinkTableNode from LinkTable
 * int Conditon(tLinkTableNode * pNode,void * args);
 */
tLinkTableNode * SearchLinkTableNode(tLinkTable *pLinkTable, int Conditon(tLinkTableNode * pNode, void * args), void * args);
/*
 * get LinkTableHead
 */
tLinkTableNode * GetLinkTableHead(tLinkTable *pLinkTable);
/*
 * get next LinkTableNode
 */
tLinkTableNode * GetNextLinkTableNode(tLinkTable *pLinkTable,tLinkTableNode * pNode);

#endif /* _LINK_TABLE_H_ */

$>vi menu.c
-------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "linktable.h"
#include "menu.h"

tLinkTable * head = NULL;
int Help();
int Quit();

#define CMD_MAX_LEN         1024
#define CMD_MAX_ARGV_NUM     32
#define DESC_LEN            1024
#define CMD_NUM             10

char prompt[CMD_MAX_LEN] = "Input Cmd >";

/* data struct and its operations */

typedef struct DataNode
{
    tLinkTableNode * pNext;
    char*   cmd;
    char*   desc;
    int     (*handler)(int argc, char *argv[]);
} tDataNode;

int SearchConditon(tLinkTableNode * pLinkTableNode,void * arg)
{
    char * cmd = (char*)arg;
    tDataNode * pNode = (tDataNode *)pLinkTableNode;
    if(strcmp(pNode->cmd, cmd) == 0)
    {
        return  SUCCESS;  
    }
    return FAILURE;           
}
/* find a cmd in the linklist and return the datanode pointer */
tDataNode* FindCmd(tLinkTable * head, char * cmd)
{
    tDataNode * pNode = (tDataNode*)GetLinkTableHead(head);
    while(pNode != NULL)
    {
        if(!strcmp(pNode->cmd, cmd))
        {
            return  pNode;  
        }
        pNode = (tDataNode*)GetNextLinkTableNode(head,(tLinkTableNode *)pNode);
    }
    return NULL;
}

/* show all cmd in listlist */
int ShowAllCmd(tLinkTable * head)
{
    tDataNode * pNode = (tDataNode*)GetLinkTableHead(head);
    while(pNode != NULL)
    {
        printf("%s - %s\n", pNode->cmd, pNode->desc);
        pNode = (tDataNode*)GetNextLinkTableNode(head,(tLinkTableNode *)pNode);
    }
    return 0;
}

int Help(int argc, char *argv[])
{
    ShowAllCmd(head);
    return 0; 
}

int SetPrompt(char * p)
{
    if (p == NULL)
    {
        return 0;
    }
    strcpy(prompt,p);
    return 0;
}
/* add cmd to menu */
int MenuConfig(char * cmd, char * desc, int (*handler)())
{
    tDataNode* pNode = NULL;
    if ( head == NULL)
    {
        head = CreateLinkTable();
        pNode = (tDataNode*)malloc(sizeof(tDataNode));
        pNode->cmd = "help";
        pNode->desc = "Menu List:";
        pNode->handler = Help;
        AddLinkTableNode(head,(tLinkTableNode *)pNode);
    }
    pNode = (tDataNode*)malloc(sizeof(tDataNode));
    pNode->cmd = cmd;
    pNode->desc = desc;
    pNode->handler = handler; 
    AddLinkTableNode(head,(tLinkTableNode *)pNode);
    return 0; 
}


/* Menu Engine Execute */
int ExecuteMenu()
{
   /* cmd line begins */
    while(1)
    {
        int argc = 0;
        char *argv[CMD_MAX_ARGV_NUM];
        char cmd[CMD_MAX_LEN];
        char *pcmd = NULL;
        printf("%s",prompt);
        /* scanf("%s", cmd); */
        pcmd = fgets(cmd, CMD_MAX_LEN, stdin);
        if(pcmd == NULL)
        {
            continue;
        }
        /* convert cmd to argc/argv */
        pcmd = strtok(pcmd," ");
        while(pcmd != NULL && argc < CMD_MAX_ARGV_NUM)
        {
            argv[argc] = pcmd;
            argc++;
            pcmd = strtok(NULL," ");
        }
        if(argc == 1)
        {
            int len = strlen(argv[0]);
            *(argv[0] + len - 1) = '\0';
        }
        tDataNode *p = (tDataNode*)SearchLinkTableNode(head,SearchConditon,(void*)argv[0]);
        if( p == NULL)
        {
            printf("This is a wrong cmd!\n ");
            continue;
        }
        
        if(p->handler != NULL) 
        { 
            p->handler(argc, argv);
        }
    }

$>vi menu.h
-------------
/* Set Input Prompt */
int SetPrompt(char * p);
/* add cmd to menu */
int MenuConfig(char * cmd, char * desc, int (*handler)());

/* Menu Engine Execute */
int ExecuteMenu();

$>vi test.c
-------------
#include <stdio.h>
#include <stdlib.h>
#include "menu.h"

#define FONTSIZE 10
int PrintMenuOS()
{
    int i, j;
    char data_M[FONTSIZE][FONTSIZE] =
    {
        "          ",
        "  *    *  ",
        " ***  *** ",
        " * *  * * ",
        " * *  * * ",
        " *  **  * ",
        " *      * ",
        " *      * ",
        " *      * ",
        "          "
    };
    char data_e[FONTSIZE][FONTSIZE] =
    {
        "          ",
        "          ",
        "    **    ",
        "   *  *   ",
        "  *    *  ",
        "  ******  ",
        "  *       ",
        "   *      ",
        "    ***   ",
        "          "
    };
    char data_n[FONTSIZE][FONTSIZE] =
    {
        "          ",
        "          ",
        "    **    ",
        "   *  *   ",
        "  *    *  ",
        "  *    *  ",
        "  *    *  ",
        "  *    *  ",
        "  *    *  ",
        "          "
    };
    char data_u[FONTSIZE][FONTSIZE] =
    {
        "          ",
        "          ",
        "  *    *  ",
        "  *    *  ",
        "  *    *  ",
        "  *    *  ",
        "  *    *  ",
        "   *  **  ",
        "    **  * ",
        "          "
    };
    char data_O[FONTSIZE][FONTSIZE] =
    {
        "          ",
        "   ****   ",
        "  *    *  ",
        " *      * ",
        " *      * ",
        " *      * ",
        " *      * ",
        "  *    *  ",
        "   ****   ",
        "          "
    };
    char data_S[FONTSIZE][FONTSIZE] =
    {
        "          ",
        "    ****  ",
        "   **     ",
        "  **      ",
        "   ***    ",
        "     **   ",
        "      **  ",
        "     **   ",
        "  ****    ",
        "          "
    };

    for(i=0; i<FONTSIZE; i++)
    {
        for(j=0; j<FONTSIZE; j++)
        {
            printf("%c", data_M[i][j]);
        }
        for(j=0; j<FONTSIZE; j++)
        {
            printf("%c", data_e[i][j]);
        }
        for(j=0; j<FONTSIZE; j++)
        {
            printf("%c", data_n[i][j]);
        }
        for(j=0; j<FONTSIZE; j++)
        {
            printf("%c", data_u[i][j]);
        }
        for(j=0; j<FONTSIZE; j++)
        {
            printf("%c", data_O[i][j]);
        }
        for(j=0; j<FONTSIZE; j++)
        {
            printf("%c", data_S[i][j]);
        }
        printf("\n");
    }
    return 0;
}

int Quit(int argc, char *argv[])
{
    /* add XXX clean ops */
    exit(0);
}

int main()
{
    PrintMenuOS();
    SetPrompt("MenuOS>>");
    MenuConfig("version","XXX V1.0(Menu program v1.0 inside)",NULL);
    MenuConfig("quit","Quit from XXX",Quit);
    
    ExecuteMenu();
}

$>vi Makefile
-------------
CC_PTHREAD_FLAGS        = -lpthread
CC_FLAGS                = -c 
CC_OUTPUT_FLAGS         = -o
CC                      = gcc
RM                      = rm
RM_FLAGS                = -f

TARGET  =   test
OBJS    =   linktable.o  menu.o test.o

all:    $(OBJS)
    $(CC) $(CC_OUTPUT_FLAGS) $(TARGET) $(OBJS) 
rootfs:
    gcc -o init linktable.c menu.c test.c -m32 -static -lpthread
    mkdir -p ../rootfs/ && cp init ../rootfs/
    find ../rootfs/ | cpio -o -Hnewc |gzip -9 > ../rootfs.img
    qemu -kernel /path/linux-x.y.z/arch/x86/boot/bzImage -initrd /path/rootfs.img
.c.o:
    $(CC) $(CC_FLAGS) $<

clean:
    $(RM) $(RM_FLAGS)  $(OBJS) $(TARGET) *.bak
    
编译具备完全能够调试的内核
----------------
$>make i386_defconfig                        #step.1
$>make menuconfig                            #step.2,并进行"Kernel hacking  --->"设置;最后根据"调试内核必须的选项"检查是否都设置了.
$>vi /path/linux-x.y.z/Makefile              #step.3
-------------
...
HOSTCFLAGS   = -v -g -Wall -Wmissing-prototypes -Wstrict-prototypes -O0 -fomit-frame-pointer
HOSTCXXFLAGS = -v -g -O0
...

...
all: vmlinux

ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE          #每次menuconfig完后都需要重新设置.
KBUILD_CFLAGS    += -O1
else
KBUILD_CFLAGS    += -O1
endif
...

$>make CONFIG_DEBUG_SECTION_MISMATCH=y      #step.4

解压debian系统rootfs(imitrd.img)
----------------
$>mv initrd.img-3.2.0-4-amd64 imitrd.img.gz
$>gunzip initrd.img.gz
$>cpio -i --make-directories < initrd.img 

运行rootfs
----------------
$>qemu -kernel linux-x.y.z/arch/x86/boot/bzImage -initrd rootfs.img

使用rootfs调试并观察内核调用 
----------------
$>qemu -kernel /path/linux-x.y.z/arch/x86/boot/bzImage -initrd rootfs.img -s -S   #step.1,-S:freeze CPU at startup (use ’c’ to start execution),-s:shorthand for -gdb tcp::1234 若不想使用1234端口,则可以使用-gdb tcp:xxxx来取代-s选项.
$>gdb                                                                             #step.2
gdb>file /path/linux-x.y.z/vmlinux                                                #在gdb界面中targe remote之前加载符号表.
gdb>target remote:1234                                                            #建立gdb和gdbserver之间的连接,按c 让qemu上的Linux继续运行.
gdb>break start_kernel                                                            #断点的设置可以在target remote之前,也可以在之后.

注意:实现此方法需要在原生的基础上编译内核,然后使用rootfs.img.

gdb调试内核实践
----------------
3972 void lockdep_init(void)
3973 {
    int i;

    /*
     * Some architectures have their own start_kernel()
     * code which calls lockdep_init(), while we also
     * call lockdep_init() from the start_kernel() itself,
     * and we want to initialize the hashes only once:
     */
    if (lockdep_initialized)
        return;

    for (i = 0; i < CLASSHASH_SIZE; i++)
        INIT_LIST_HEAD(classhash_table + i);

    for (i = 0; i < CHAINHASH_SIZE; i++)
        INIT_LIST_HEAD(chainhash_table + i);

    lockdep_initialized = 1;
3992 }

$>b lockdep_init
$>bt
---------
#0  lockdep_init () at kernel/lockdep.c:3985
#1  0xc1a7170c in start_kernel () at init/main.c:479
#2  0xc1a71362 in i386_start_kernel () at arch/x86/kernel/head32.c:49
#3  0x00000000 in ?? ()

$>p lockdep_init
$1 = {void (void)} 0xc108806d <lockdep_init>

$>p $eip
---------
$2 = (void (*)()) 0xc1088094 <lockdep_init+39>

$>disassemble /r 0xc108806d,0xc1088094
---------
Dump of assembler code from 0xc108806d to 0xc1088094:
   0xc108806d <lockdep_init+0>:    55    push   %ebp
   0xc108806e <lockdep_init+1>:    89 e5    mov    %esp,%ebp
   0xc1088070 <lockdep_init+3>:    83 3d a0 51 18 c2 00    cmpl   $0x0,0xc21851a0
   0xc1088077 <lockdep_init+10>:    75 57    jne    0xc10880d0 <lockdep_init+99>
   0xc1088079 <lockdep_init+12>:    b9 00 00 00 00    mov    $0x0,%ecx
   0xc108807e <lockdep_init+17>:    b8 00 00 00 00    mov    $0x0,%eax
   0xc1088083 <lockdep_init+22>:    8d 14 cd a0 d1 17 c2    lea    -0x3de82e60(,%ecx,8),%edx
   0xc108808a <lockdep_init+29>:    89 14 cd a0 d1 17 c2    mov    %edx,-0x3de82e60(,%ecx,8)
   0xc1088091 <lockdep_init+36>:    89 52 04    mov    %edx,0x4(%edx)
End of assembler dump.

$>disassemble /m 0xc108806d,0xc1088094
---------
3973    {
   0xc108806d <lockdep_init+0>:    push   %ebp
   0xc108806e <lockdep_init+1>:    mov    %esp,%ebp

3974        int i;
3975    
3976        /*
3977         * Some architectures have their own start_kernel()
3978         * code which calls lockdep_init(), while we also
3979         * call lockdep_init() from the start_kernel() itself,
3980         * and we want to initialize the hashes only once:
3981         */
3982        if (lockdep_initialized)
   0xc1088070 <lockdep_init+3>:    cmpl   $0x0,0xc21851a0
   0xc1088077 <lockdep_init+10>:    jne    0xc10880d0 <lockdep_init+99>
   0xc108807e <lockdep_init+17>:    mov    $0x0,%eax

3983            return;
3984    
3985        for (i = 0; i < CLASSHASH_SIZE; i++)
   0xc1088079 <lockdep_init+12>:    mov    $0x0,%ecx

3986            INIT_LIST_HEAD(classhash_table + i);
   0xc1088083 <lockdep_init+22>:    lea    -0x3de82e60(,%ecx,8),%edx

End of assembler dump.

$>disassemble /m 0xc108806d,+100                                                  #推荐这个方法阅读反汇编代码.
---------
Dump of assembler code from 0xc108806d to 0xc10880d1:
3973    {
   0xc108806d <lockdep_init+0>:    push   %ebp
   0xc108806e <lockdep_init+1>:    mov    %esp,%ebp

3974        int i;
3975    
3976        /*
3977         * Some architectures have their own start_kernel()
3978         * code which calls lockdep_init(), while we also
3979         * call lockdep_init() from the start_kernel() itself,
3980         * and we want to initialize the hashes only once:
3981         */
3982        if (lockdep_initialized)
   0xc1088070 <lockdep_init+3>:    cmpl   $0x0,0xc21851a0
   0xc1088077 <lockdep_init+10>:    jne    0xc10880d0 <lockdep_init+99>
   0xc108807e <lockdep_init+17>:    mov    $0x0,%eax

3983            return;
3984    
3985        for (i = 0; i < CLASSHASH_SIZE; i++)
   0xc1088079 <lockdep_init+12>:    mov    $0x0,%ecx
=> 0xc1088094 <lockdep_init+39>:    add    $0x1,%eax                         
   0xc1088097 <lockdep_init+42>:    mov    %eax,%ecx
   0xc1088099 <lockdep_init+44>:    cmp    $0x1000,%eax
   0xc108809e <lockdep_init+49>:    jne    0xc1088083 <lockdep_init+22>
   0xc10880a5 <lockdep_init+56>:    mov    $0x0,%ax

3986            INIT_LIST_HEAD(classhash_table + i);
   0xc1088083 <lockdep_init+22>:    lea    -0x3de82e60(,%ecx,8),%edx

3987    
3988        for (i = 0; i < CHAINHASH_SIZE; i++)
   0xc10880a0 <lockdep_init+51>:    mov    $0x0,%ecx
   0xc10880ba <lockdep_init+77>:    add    $0x1,%eax
   0xc10880bd <lockdep_init+80>:    mov    %eax,%ecx
   0xc10880bf <lockdep_init+82>:    cmp    $0x4000,%eax
   0xc10880c4 <lockdep_init+87>:    jne    0xc10880a9 <lockdep_init+60>

3989            INIT_LIST_HEAD(chainhash_table + i);
   0xc10880a9 <lockdep_init+60>:    lea    -0x3de7ae40(,%ecx,8),%edx

3990    
3991        lockdep_initialized = 1;
   0xc10880c6 <lockdep_init+89>:    movl   $0x1,0xc21851a0

3992    }
   0xc10880d0 <lockdep_init+99>:    pop    %ebp
   0xc10880d1 <lockdep_init+100>:    ret    

End of assembler dump.

$>p *0xc21851a0
---------
$3 = 0

$>p (int)$eax
---------
$4 = 3

$>x /wx 0xc21851a0                                                                   #查看内存.
$>x /8x $esp
$>x /16x $esp+12
$>x /16s $esp+12                                                                     #以字符串形式显示指定地址处的数据.
$>x /16i $esp+12                                                                     #以指令形式显示指定地址处的数据(16条).

$>set $eax 0xc10880bf                                                                #修改寄存器的值.
$>set {unsigned int}0xc21851a0=0x1                                                   #修改内存值.
$>watch *(unsigned int *)0xc21851a0 == 0x3

$>p $pc                                                                              #查看当前pc寄存器的值,关注pc值非常重要.
$>display $pc                                                                        #观察pc寄存器的值.

$>i r                                                                                #查看寄存器.
$>i r a
$>i r esp
$>i r pc

$>info register                                                                      #查看所有寄存器.
---------
eax            0x4    4
ecx            0x4    4
edx            0xc217d1c0    -1038626368
ebx            0x800    2048
esp            0xc19e7fcc    0xc19e7fcc
ebp            0xc19e7fcc    0xc19e7fcc
esi            0x20800    133120
edi            0xc19e9800    -1046571008
eip            0xc1088094    0xc1088094 <lockdep_init+39>
eflags         0x200083    [ CF SF ID ]
cs             0x60    96
ss             0x68    104
ds             0x7b    123
es             0x7b    123
fs             0xd8    216
gs             0x0    0

$>info all-registers
---------
eax            0x4    4
ecx            0x4    4
edx            0xc217d1c0    -1038626368
ebx            0x800    2048
esp            0xc19e7fcc    0xc19e7fcc
ebp            0xc19e7fcc    0xc19e7fcc
esi            0x20800    133120
edi            0xc19e9800    -1046571008
eip            0xc1088094    0xc1088094 <lockdep_init+39>
eflags         0x200083    [ CF SF ID ]
cs             0x60    96
ss             0x68    104
ds             0x7b    123
es             0x7b    123
fs             0xd8    216
gs             0x0    0
st0            0    (raw 0x00000000000000000000)
st1            0    (raw 0x00000000000000000000)
st2            0    (raw 0x00000000000000000000)
st3            0    (raw 0x00000000000000000000)
st4            0    (raw 0x00000000000000000000)
st5            0    (raw 0x00000000000000000000)
st6            0    (raw 0x00000000000000000000)
st7            0    (raw 0x00000000000000000000)
fctrl          0x37f    895
fstat          0x0    0
ftag           0x0    0
fiseg          0x0    0
fioff          0x0    0
foseg          0x0    0
fooff          0x0    0
fop            0x0    0
xmm0           {
  v4_float =     {[0x0] = 0x0,
    [0x1] = 0x0,
    [0x2] = 0x0,
    [0x3] = 0x0}, 
  v2_double =     {[0x0] = 0x0,
    [0x1] = 0x0}, 
  v16_int8 =     {[0x0] = 0x0 <repeats 16 times>}, 
  v8_int16 =     {[0x0] = 0x0,
    [0x1] = 0x0,
    [0x2] = 0x0,
    [0x3] = 0x0,
    [0x4] = 0x0,
    [0x5] = 0x0,
    [0x6] = 0x0,
    [0x7] = 0x0}, 
  v4_int32 =     {[0x0] = 0x0,
    [0x1] = 0x0,
    [0x2] = 0x0,
    [0x3] = 0x0}, 
  v2_int64 =     {[0x0] = 0x0,
    [0x1] = 0x0}, 
  uint128 = 0x00000000000000000000000000000000
}
xmm1           {
  v4_float =     {[0x0] = 0x0,
    [0x1] = 0x0,
    [0x2] = 0x0,
    [0x3] = 0x0}, 
  v2_double =     {[0x0] = 0x0,
    [0x1] = 0x0}, 
  v16_int8 =     {[0x0] = 0x0 <repeats 16 times>}, 
  v8_int16 =     {[0x0] = 0x0,
    [0x1] = 0x0,
    [0x2] = 0x0,
    [0x3] = 0x0,
    [0x4] = 0x0,
    [0x5] = 0x0,
    [0x6] = 0x0,
    [0x7] = 0x0}, 
  v4_int32 =     {[0x0] = 0x0,
    [0x1] = 0x0,
    [0x2] = 0x0,
    [0x3] = 0x0}, 
  v2_int64 =     {[0x0] = 0x0,
    [0x1] = 0x0}, 
  uint128 = 0x00000000000000000000000000000000
}
xmm2           {
  v4_float =     {[0x0] = 0x0,
    [0x1] = 0x0,
    [0x2] = 0x0,
    [0x3] = 0x0}, 
  v2_double =     {[0x0] = 0x0,
    [0x1] = 0x0}, 
  v16_int8 =     {[0x0] = 0x0 <repeats 16 times>}, 
  v8_int16 =     {[0x0] = 0x0,
    [0x1] = 0x0,
    [0x2] = 0x0,
    [0x3] = 0x0,
    [0x4] = 0x0,
    [0x5] = 0x0,
    [0x6] = 0x0,
    [0x7] = 0x0}, 
  v4_int32 =     {[0x0] = 0x0,
    [0x1] = 0x0,
    [0x2] = 0x0,
    [0x3] = 0x0}, 
  v2_int64 =     {[0x0] = 0x0,
    [0x1] = 0x0}, 
  uint128 = 0x00000000000000000000000000000000
}
xmm3           {
  v4_float =     {[0x0] = 0x0,
    [0x1] = 0x0,
    [0x2] = 0x0,
    [0x3] = 0x0}, 
  v2_double =     {[0x0] = 0x0,
    [0x1] = 0x0}, 
  v16_int8 =     {[0x0] = 0x0 <repeats 16 times>}, 
  v8_int16 =     {[0x0] = 0x0,
    [0x1] = 0x0,
    [0x2] = 0x0,
    [0x3] = 0x0,
    [0x4] = 0x0,
    [0x5] = 0x0,
    [0x6] = 0x0,
    [0x7] = 0x0}, 
  v4_int32 =     {[0x0] = 0x0,
    [0x1] = 0x0,
    [0x2] = 0x0,
    [0x3] = 0x0}, 
  v2_int64 =     {[0x0] = 0x0,
    [0x1] = 0x0}, 
  uint128 = 0x00000000000000000000000000000000
}
xmm4           {
  v4_float =     {[0x0] = 0x0,
    [0x1] = 0x0,
    [0x2] = 0x0,
    [0x3] = 0x0}, 
  v2_double =     {[0x0] = 0x0,
    [0x1] = 0x0}, 
  v16_int8 =     {[0x0] = 0x0 <repeats 16 times>}, 
  v8_int16 =     {[0x0] = 0x0,
    [0x1] = 0x0,
    [0x2] = 0x0,
    [0x3] = 0x0,
    [0x4] = 0x0,
    [0x5] = 0x0,
    [0x6] = 0x0,
    [0x7] = 0x0}, 
  v4_int32 =     {[0x0] = 0x0,
    [0x1] = 0x0,
    [0x2] = 0x0,
    [0x3] = 0x0}, 
  v2_int64 =     {[0x0] = 0x0,
    [0x1] = 0x0}, 
  uint128 = 0x00000000000000000000000000000000
}
xmm5           {
  v4_float =     {[0x0] = 0x0,
    [0x1] = 0x0,
    [0x2] = 0x0,
    [0x3] = 0x0}, 
  v2_double =     {[0x0] = 0x0,
    [0x1] = 0x0}, 
  v16_int8 =     {[0x0] = 0x0 <repeats 16 times>}, 
  v8_int16 =     {[0x0] = 0x0,
    [0x1] = 0x0,
    [0x2] = 0x0,
    [0x3] = 0x0,
    [0x4] = 0x0,
    [0x5] = 0x0,
    [0x6] = 0x0,
    [0x7] = 0x0}, 
  v4_int32 =     {[0x0] = 0x0,
    [0x1] = 0x0,
    [0x2] = 0x0,
    [0x3] = 0x0}, 
  v2_int64 =     {[0x0] = 0x0,
    [0x1] = 0x0}, 
  uint128 = 0x00000000000000000000000000000000
}
xmm6           {
  v4_float =     {[0x0] = 0x0,
    [0x1] = 0x0,
    [0x2] = 0x0,
    [0x3] = 0x0}, 
  v2_double =     {[0x0] = 0x0,
    [0x1] = 0x0}, 
  v16_int8 =     {[0x0] = 0x0 <repeats 16 times>}, 
  v8_int16 =     {[0x0] = 0x0,
    [0x1] = 0x0,
    [0x2] = 0x0,
    [0x3] = 0x0,
    [0x4] = 0x0,
    [0x5] = 0x0,
    [0x6] = 0x0,
    [0x7] = 0x0}, 
  v4_int32 =     {[0x0] = 0x0,
    [0x1] = 0x0,
    [0x2] = 0x0,
    [0x3] = 0x0}, 
  v2_int64 =     {[0x0] = 0x0,
    [0x1] = 0x0}, 
  uint128 = 0x00000000000000000000000000000000
}
xmm7           {
  v4_float =     {[0x0] = 0x0,
    [0x1] = 0x0,
    [0x2] = 0x0,
    [0x3] = 0x0}, 
  v2_double =     {[0x0] = 0x0,
    [0x1] = 0x0}, 
  v16_int8 =     {[0x0] = 0x0 <repeats 16 times>}, 
  v8_int16 =     {[0x0] = 0x0,
    [0x1] = 0x0,
    [0x2] = 0x0,
    [0x3] = 0x0,
    [0x4] = 0x0,
    [0x5] = 0x0,
    [0x6] = 0x0,
    [0x7] = 0x0}, 
  v4_int32 =     {[0x0] = 0x0,
    [0x1] = 0x0,
    [0x2] = 0x0,
    [0x3] = 0x0}, 
  v2_int64 =     {[0x0] = 0x0,
    [0x1] = 0x0}, 
  uint128 = 0x00000000000000000000000000000000
}
mxcsr          0x1f80    [ IM DM ZM OM UM PM ]
mm0            {
  uint64 = 0x0, 
  v2_int32 =     {[0x0] = 0x0,
    [0x1] = 0x0}, 
  v4_int16 =     {[0x0] = 0x0,
    [0x1] = 0x0,
    [0x2] = 0x0,
    [0x3] = 0x0}, 
  v8_int8 =     {[0x0] = 0x0,
    [0x1] = 0x0,
    [0x2] = 0x0,
    [0x3] = 0x0,
    [0x4] = 0x0,
    [0x5] = 0x0,
    [0x6] = 0x0,
    [0x7] = 0x0}
}
mm1            {
  uint64 = 0x0, 
  v2_int32 =     {[0x0] = 0x0,
    [0x1] = 0x0}, 
  v4_int16 =     {[0x0] = 0x0,
    [0x1] = 0x0,
    [0x2] = 0x0,
    [0x3] = 0x0}, 
  v8_int8 =     {[0x0] = 0x0,
    [0x1] = 0x0,
    [0x2] = 0x0,
    [0x3] = 0x0,
    [0x4] = 0x0,
    [0x5] = 0x0,
    [0x6] = 0x0,
    [0x7] = 0x0}
}
mm2            {
  uint64 = 0x0, 
  v2_int32 =     {[0x0] = 0x0,
    [0x1] = 0x0}, 
  v4_int16 =     {[0x0] = 0x0,
    [0x1] = 0x0,
    [0x2] = 0x0,
    [0x3] = 0x0}, 
  v8_int8 =     {[0x0] = 0x0,
    [0x1] = 0x0,
    [0x2] = 0x0,
    [0x3] = 0x0,
    [0x4] = 0x0,
    [0x5] = 0x0,
    [0x6] = 0x0,
    [0x7] = 0x0}
}
mm3            {
  uint64 = 0x0, 
  v2_int32 =     {[0x0] = 0x0,
    [0x1] = 0x0}, 
  v4_int16 =     {[0x0] = 0x0,
    [0x1] = 0x0,
    [0x2] = 0x0,
    [0x3] = 0x0}, 
  v8_int8 =     {[0x0] = 0x0,
    [0x1] = 0x0,
    [0x2] = 0x0,
    [0x3] = 0x0,
    [0x4] = 0x0,
    [0x5] = 0x0,
    [0x6] = 0x0,
    [0x7] = 0x0}
}
mm4            {
  uint64 = 0x0, 
  v2_int32 =     {[0x0] = 0x0,
    [0x1] = 0x0}, 
  v4_int16 =     {[0x0] = 0x0,
    [0x1] = 0x0,
    [0x2] = 0x0,
    [0x3] = 0x0}, 
  v8_int8 =     {[0x0] = 0x0,
    [0x1] = 0x0,
    [0x2] = 0x0,
    [0x3] = 0x0,
    [0x4] = 0x0,
    [0x5] = 0x0,
    [0x6] = 0x0,
    [0x7] = 0x0}
}
mm5            {
  uint64 = 0x0, 
  v2_int32 =     {[0x0] = 0x0,
    [0x1] = 0x0}, 
  v4_int16 =     {[0x0] = 0x0,
    [0x1] = 0x0,
    [0x2] = 0x0,
    [0x3] = 0x0}, 
  v8_int8 =     {[0x0] = 0x0,
    [0x1] = 0x0,
    [0x2] = 0x0,
    [0x3] = 0x0,
    [0x4] = 0x0,
    [0x5] = 0x0,
    [0x6] = 0x0,
    [0x7] = 0x0}
}
mm6            {
  uint64 = 0x0, 
  v2_int32 =     {[0x0] = 0x0,
    [0x1] = 0x0}, 
  v4_int16 =     {[0x0] = 0x0,
    [0x1] = 0x0,
    [0x2] = 0x0,
    [0x3] = 0x0}, 
  v8_int8 =     {[0x0] = 0x0,
    [0x1] = 0x0,
    [0x2] = 0x0,
    [0x3] = 0x0,
    [0x4] = 0x0,
    [0x5] = 0x0,
    [0x6] = 0x0,
    [0x7] = 0x0}
}
mm7            {
  uint64 = 0x0, 
  v2_int32 =     {[0x0] = 0x0,
    [0x1] = 0x0}, 
  v4_int16 =     {[0x0] = 0x0,
    [0x1] = 0x0,
    [0x2] = 0x0,
    [0x3] = 0x0}, 
  v8_int8 =     {[0x0] = 0x0,
    [0x1] = 0x0,
    [0x2] = 0x0,
    [0x3] = 0x0,
    [0x4] = 0x0,
    [0x5] = 0x0,
    [0x6] = 0x0,
    [0x7] = 0x0}
}

注意:调试内核的是无法输出变量值的,使用p打印变量都会出现"$1 = <optimized out>".

printk函数打印
----------------
KERN_EMERG                 #紧急事件消息,系统崩溃之前提示.
KERN_ALERT                 #报告消息,表示立即采取措施.
KERN_CRIT                  #临界条件,通常涉及严重的硬件或软件操作失败.
KERN_ERR                   #错误条件,驱动程序常用KERN_ERR报告硬件错误.
KERN_WARNING               #警告条件.
KERN_NOTICE                #正常但又重要的信息.
KERN_INFO                  #提示信息.
KERN_DEBUG                 #调试级别信息(hacking模式下才显示).

注意:内核代码开始研究前,最佳入手方法应该从init/main.c,init/do_mounts.c开始.

分析内核中断系统调用
----------------
$>make i386_defconfig      #step.1
$>make menuconfig          #step.2,并进行"Kernel hacking  --->"设置;最后根据"调试内核必须的选项"检查是否都设置了.
$>make                     #step.3

$>vi times.c
-------------
#include <stdio.h>
#include <time.h>

int main(int argc,char **argv)
{
    time_t times;
    struct tm *t;

    times=time(0);
    t=localtime(&times);

    printf("%d:%d:%d %d:%d:%d\n", t->tm_year + 1900, t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
    return 0;
}

$>gcc times.c -o rootfs/init -m32 -static -lpthread

$>vi times-asm.c
-------------
#include <stdio.h>
#include <time.h>

int main(int argc,char **argv)
{
    time_t times;
    struct tm *t;

    asm volatile                       //触发0xd(13)系统调用.
    (
        "mov $0,%%ebx\n\t"
        "mov $0xd,%%eax\n\t"
        "int $0x80\n\t"
        "mov %%eax,%0\n\t"
        : "=m" (times)
    );

    t=localtime(&times);
    printf("%d:%d:%d %d:%d:%d\n", t->tm_year + 1900, t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
    return 0;
}

$>gcc times-asm.c -o times-asm -m32 -static -lpthread

$>vi forks.c
-------------
#include <stdio.h>
#include <time.h>
#include <unistd.h>

int main(int argc,char **argv)
{
    int pid;

    pid=fork();
    if (pid<0) 
    {
        fprintf(stderr,"Fork failed!");
        exit(-1);
    }
    else if(pid==0)
    {
        printf("This is child process!\n");
    }
    else
    {
        printf("This is parent process!\n");
        wait(0);
        printf("Child complete!\n");
    }
    return 0;
}

$>gcc forks.c -o forks -m32 -static -lpthread
以上代码写完后制作rootfs并不能直接运行,需要继续下面的操作.

$>vi execute.c
-------------
#include <stdio.h>
#include <time.h>
#include <unistd.h>

int main(int argc,char **argv)
{
    int pid;

    pid=fork();
    if(pid<0)
    {
        fprintf(stderr,"Fork Failed!");
        exit(-1);
    }
    else if(pid==0)
    {
        printf("This is Child Process!\n");
        execlp("/xx-name","xx-name",NULL);    //跟踪"execve"系统调用.
    }
    else
    {
        printf("This is Parent Process!\n");
    }
    return 0;
}

$>gcc execute.c -o execute -m32 -static -lpthread

$>vi xx-name.c
-------------
#include <stdio.h>
#include <time.h>
#include <unistd.h>

int main(int argc,char **argv)
{
    printf("Hello World!\n");
    return 0;
}

$>gcc xx-name.c -o xx-name -m32 -static -lpthread

vi linktable.c
-------------
#include<stdio.h>
#include<stdlib.h>
#include <pthread.h>
#include"linktable.h"

/*
 * LinkTable Type
 */
struct LinkTable
{
    tLinkTableNode *pHead;
    tLinkTableNode *pTail;
    int                SumOfNode;
    pthread_mutex_t mutex;

};

/*
 * Create a LinkTable
 */
tLinkTable * CreateLinkTable()
{
    tLinkTable * pLinkTable = (tLinkTable *)malloc(sizeof(tLinkTable));
    if(pLinkTable == NULL)
    {
        return NULL;
    }
    pLinkTable->pHead = NULL;
    pLinkTable->pTail = NULL;
    pLinkTable->SumOfNode = 0;
    pthread_mutex_init(&(pLinkTable->mutex), NULL);
    return pLinkTable;
}

/*
 * Delete a LinkTable
 */
int DeleteLinkTable(tLinkTable *pLinkTable)
{
    if(pLinkTable == NULL)
    {
        return FAILURE;
    }
    while(pLinkTable->pHead != NULL)
    {
        tLinkTableNode * p = pLinkTable->pHead;
        pthread_mutex_lock(&(pLinkTable->mutex));
        pLinkTable->pHead = pLinkTable->pHead->pNext;
        pLinkTable->SumOfNode -= 1 ;
        pthread_mutex_unlock(&(pLinkTable->mutex));
        free(p);
    }
    pLinkTable->pHead = NULL;
    pLinkTable->pTail = NULL;
    pLinkTable->SumOfNode = 0;
    pthread_mutex_destroy(&(pLinkTable->mutex));
    free(pLinkTable);
    return SUCCESS;        
}

/*
 * Add a LinkTableNode to LinkTable
 */
int AddLinkTableNode(tLinkTable *pLinkTable,tLinkTableNode * pNode)
{
    if(pLinkTable == NULL || pNode == NULL)
    {
        return FAILURE;
    }
    pNode->pNext = NULL;
    pthread_mutex_lock(&(pLinkTable->mutex));
    if(pLinkTable->pHead == NULL)
    {
        pLinkTable->pHead = pNode;
    }
    if(pLinkTable->pTail == NULL)
    {
        pLinkTable->pTail = pNode;
    }
    else
    {
        pLinkTable->pTail->pNext = pNode;
        pLinkTable->pTail = pNode;
    }
    pLinkTable->SumOfNode += 1 ;
    pthread_mutex_unlock(&(pLinkTable->mutex));
    return SUCCESS;        
}

/*
 * Delete a LinkTableNode from LinkTable
 */
int DelLinkTableNode(tLinkTable *pLinkTable,tLinkTableNode * pNode)
{
    if(pLinkTable == NULL || pNode == NULL)
    {
        return FAILURE;
    }
    pthread_mutex_lock(&(pLinkTable->mutex));
    if(pLinkTable->pHead == pNode)
    {
        pLinkTable->pHead = pLinkTable->pHead->pNext;
        pLinkTable->SumOfNode -= 1 ;
        if(pLinkTable->SumOfNode == 0)
        {
            pLinkTable->pTail = NULL;    
        }
        pthread_mutex_unlock(&(pLinkTable->mutex));
        return SUCCESS;
    }
    tLinkTableNode * pTempNode = pLinkTable->pHead;
    while(pTempNode != NULL)
    {    
        if(pTempNode->pNext == pNode)
        {
            pTempNode->pNext = pTempNode->pNext->pNext;
            pLinkTable->SumOfNode -= 1 ;
            if(pLinkTable->SumOfNode == 0)
            {
                pLinkTable->pTail = NULL;    
            }
            pthread_mutex_unlock(&(pLinkTable->mutex));
            return SUCCESS;                    
        }
        pTempNode = pTempNode->pNext;
    }
    pthread_mutex_unlock(&(pLinkTable->mutex));
    return FAILURE;        
}

/*
 * Search a LinkTableNode from LinkTable
 * int Conditon(tLinkTableNode * pNode);
 */
tLinkTableNode * SearchLinkTableNode(tLinkTable *pLinkTable, int Conditon(tLinkTableNode * pNode, void * args), void * args)
{
    if(pLinkTable == NULL || Conditon == NULL)
    {
        return NULL;
    }
    tLinkTableNode * pNode = pLinkTable->pHead;
    while(pNode != NULL)
    {    
        if(Conditon(pNode,args) == SUCCESS)
        {
            return pNode;                    
        }
        pNode = pNode->pNext;
    }
    return NULL;
}

/*
 * get LinkTableHead
 */
tLinkTableNode * GetLinkTableHead(tLinkTable *pLinkTable)
{
    if(pLinkTable == NULL)
    {
        return NULL;
    }    
    return pLinkTable->pHead;
}

/*
 * get next LinkTableNode
 */
tLinkTableNode * GetNextLinkTableNode(tLinkTable *pLinkTable,tLinkTableNode * pNode)
{
    if(pLinkTable == NULL || pNode == NULL)
    {
        return NULL;
    }
    tLinkTableNode * pTempNode = pLinkTable->pHead;
    while(pTempNode != NULL)
    {    
        if(pTempNode == pNode)
        {
            return pTempNode->pNext;                    
        }
        pTempNode = pTempNode->pNext;
    }
    return NULL;
}

$>vi linktable.h
-------------
#ifndef _LINK_TABLE_H_
#define _LINK_TABLE_H_

#include <pthread.h>

#define SUCCESS 0
#define FAILURE (-1)

/*
 * LinkTable Node Type
 */
typedef struct LinkTableNode
{
    struct LinkTableNode * pNext;
}tLinkTableNode;

/*
 * LinkTable Type
 */
typedef struct LinkTable tLinkTable;

/*
 * Create a LinkTable
 */
tLinkTable * CreateLinkTable();
/*
 * Delete a LinkTable
 */
int DeleteLinkTable(tLinkTable *pLinkTable);
/*
 * Add a LinkTableNode to LinkTable
 */
int AddLinkTableNode(tLinkTable *pLinkTable,tLinkTableNode * pNode);
/*
 * Delete a LinkTableNode from LinkTable
 */
int DelLinkTableNode(tLinkTable *pLinkTable,tLinkTableNode * pNode);
/*
 * Search a LinkTableNode from LinkTable
 * int Conditon(tLinkTableNode * pNode,void * args);
 */
tLinkTableNode * SearchLinkTableNode(tLinkTable *pLinkTable, int Conditon(tLinkTableNode * pNode, void * args), void * args);
/*
 * get LinkTableHead
 */
tLinkTableNode * GetLinkTableHead(tLinkTable *pLinkTable);
/*
 * get next LinkTableNode
 */
tLinkTableNode * GetNextLinkTableNode(tLinkTable *pLinkTable,tLinkTableNode * pNode);

#endif /* _LINK_TABLE_H_ */

$>vi menu.c
-------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "linktable.h"
#include "menu.h"

tLinkTable * head = NULL;
int Help();
int Quit();

#define CMD_MAX_LEN         1024
#define CMD_MAX_ARGV_NUM     32
#define DESC_LEN            1024
#define CMD_NUM             10

char prompt[CMD_MAX_LEN] = "Input Cmd >";

/* data struct and its operations */

typedef struct DataNode
{
    tLinkTableNode * pNext;
    char*   cmd;
    char*   desc;
    int     (*handler)(int argc, char *argv[]);
} tDataNode;

int SearchConditon(tLinkTableNode * pLinkTableNode,void * arg)
{
    char * cmd = (char*)arg;
    tDataNode * pNode = (tDataNode *)pLinkTableNode;
    if(strcmp(pNode->cmd, cmd) == 0)
    {
        return  SUCCESS;  
    }
    return FAILURE;           
}
/* find a cmd in the linklist and return the datanode pointer */
tDataNode* FindCmd(tLinkTable * head, char * cmd)
{
    tDataNode * pNode = (tDataNode*)GetLinkTableHead(head);
    while(pNode != NULL)
    {
        if(!strcmp(pNode->cmd, cmd))
        {
            return  pNode;  
        }
        pNode = (tDataNode*)GetNextLinkTableNode(head,(tLinkTableNode *)pNode);
    }
    return NULL;
}

/* show all cmd in listlist */
int ShowAllCmd(tLinkTable * head)
{
    tDataNode * pNode = (tDataNode*)GetLinkTableHead(head);
    while(pNode != NULL)
    {
        printf("%s - %s\n", pNode->cmd, pNode->desc);
        pNode = (tDataNode*)GetNextLinkTableNode(head,(tLinkTableNode *)pNode);
    }
    return 0;
}

int Help(int argc, char *argv[])
{
    ShowAllCmd(head);
    return 0; 
}

int SetPrompt(char * p)
{
    if (p == NULL)
    {
        return 0;
    }
    strcpy(prompt,p);
    return 0;
}
/* add cmd to menu */
int MenuConfig(char * cmd, char * desc, int (*handler)())
{
    tDataNode* pNode = NULL;
    if ( head == NULL)
    {
        head = CreateLinkTable();
        pNode = (tDataNode*)malloc(sizeof(tDataNode));
        pNode->cmd = "help";
        pNode->desc = "Menu List:";
        pNode->handler = Help;
        AddLinkTableNode(head,(tLinkTableNode *)pNode);
    }
    pNode = (tDataNode*)malloc(sizeof(tDataNode));
    pNode->cmd = cmd;
    pNode->desc = desc;
    pNode->handler = handler; 
    AddLinkTableNode(head,(tLinkTableNode *)pNode);
    return 0; 
}

/* Menu Engine Execute */
int ExecuteMenu()
{
   /* cmd line begins */
    while(1)
    {
        int argc = 0;
        char *argv[CMD_MAX_ARGV_NUM];
        char cmd[CMD_MAX_LEN];
        char *pcmd = NULL;
        printf("%s",prompt);
        /* scanf("%s", cmd); */
        pcmd = fgets(cmd, CMD_MAX_LEN, stdin);
        if(pcmd == NULL)
        {
            continue;
        }
        /* convert cmd to argc/argv */
        pcmd = strtok(pcmd," ");
        while(pcmd != NULL && argc < CMD_MAX_ARGV_NUM)
        {
            argv[argc] = pcmd;
            argc++;
            pcmd = strtok(NULL," ");
        }
        if(argc == 1)
        {
            int len = strlen(argv[0]);
            *(argv[0] + len - 1) = '\0';
        }
        tDataNode *p = (tDataNode*)SearchLinkTableNode(head,SearchConditon,(void*)argv[0]);
        if( p == NULL)
        {
            printf("This is a wrong cmd!\n ");
            continue;
        }
        
        if(p->handler != NULL) 
        { 
            p->handler(argc, argv);
        }
    }

$>vi menu.h
-------------
/* Set Input Prompt */
int SetPrompt(char * p);
/* add cmd to menu */
int MenuConfig(char * cmd, char * desc, int (*handler)());

/* Menu Engine Execute */
int ExecuteMenu();

$>vi test.c
-------------
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include "menu.h"

#define FONTSIZE 10
int PrintMenuOS()
{
    int i, j;
    char data_M[FONTSIZE][FONTSIZE] =
    {
        "          ",
        "  *    *  ",
        " ***  *** ",
        " * *  * * ",
        " * *  * * ",
        " *  **  * ",
        " *      * ",
        " *      * ",
        " *      * ",
        "          "
    };
    char data_e[FONTSIZE][FONTSIZE] =
    {
        "          ",
        "          ",
        "    **    ",
        "   *  *   ",
        "  *    *  ",
        "  ******  ",
        "  *       ",
        "   *      ",
        "    ***   ",
        "          "
    };
    char data_n[FONTSIZE][FONTSIZE] =
    {
        "          ",
        "          ",
        "    **    ",
        "   *  *   ",
        "  *    *  ",
        "  *    *  ",
        "  *    *  ",
        "  *    *  ",
        "  *    *  ",
        "          "
    };
    char data_u[FONTSIZE][FONTSIZE] =
    {
        "          ",
        "          ",
        "  *    *  ",
        "  *    *  ",
        "  *    *  ",
        "  *    *  ",
        "  *    *  ",
        "   *  **  ",
        "    **  * ",
        "          "
    };
    char data_O[FONTSIZE][FONTSIZE] =
    {
        "          ",
        "   ****   ",
        "  *    *  ",
        " *      * ",
        " *      * ",
        " *      * ",
        " *      * ",
        "  *    *  ",
        "   ****   ",
        "          "
    };
    char data_S[FONTSIZE][FONTSIZE] =
    {
        "          ",
        "    ****  ",
        "   **     ",
        "  **      ",
        "   ***    ",
        "     **   ",
        "      **  ",
        "     **   ",
        "  ****    ",
        "          "
    };

    for(i=0; i<FONTSIZE; i++)
    {
        for(j=0; j<FONTSIZE; j++)
        {
            printf("%c", data_M[i][j]);
        }
        for(j=0; j<FONTSIZE; j++)
        {
            printf("%c", data_e[i][j]);
        }
        for(j=0; j<FONTSIZE; j++)
        {
            printf("%c", data_n[i][j]);
        }
        for(j=0; j<FONTSIZE; j++)
        {
            printf("%c", data_u[i][j]);
        }
        for(j=0; j<FONTSIZE; j++)
        {
            printf("%c", data_O[i][j]);
        }
        for(j=0; j<FONTSIZE; j++)
        {
            printf("%c", data_S[i][j]);
        }
        printf("\n");
    }
    return 0;
}

int Quit(int argc, char *argv[])
{
    /* add XXX clean ops */
    exit(0);
}

int times(int argc, char *argv[])
{
  time_t times;
  struct tm *t;

  times=time(0);
  t=localtime(&times);

  printf("%d:%d:%d %d:%d:%d\n", t->tm_year + 1900, t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
  return 0;
}

int times_asm(int argc, char *argv[])
{
  time_t times;
  struct tm *t;

  asm volatile                        //触发0xd(13)系统调用.
  (
      "mov $0,%%ebx\n\t"
      "mov $0xd,%%eax\n\t"
      "int $0x80\n\t"
      "mov %%eax,%0\n\t"
      : "=m" (times)
  );

  t=localtime(&times);
  printf("%d:%d:%d %d:%d:%d\n", t->tm_year + 1900, t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
  return 0;
}

int forks(int argc,char **argv)
{
    int pid;

    pid=fork();
    if (pid<0) 
    {
        fprintf(stderr,"Fork failed!");
        exit(-1);
    }
    else if(pid==0)
    {
        printf("This is child process!\n");
    }
    else
    {
        printf("This is parent process!\n");
        wait(0);
        printf("Child complete!\n");
    }
    return 0;
}

int executes(int argc,char **argv)
{
    int pid;

    pid=fork();
    if(pid<0)
    {
        fprintf(stderr,"Fork Failed!");
        exit(-1);
    }
    else if(pid==0)
    {
        printf("This is Child Process!\n");
        execlp("/xx-name","xx-name",NULL);    //跟踪"execve"系统调用.
    }
    else
    {
        printf("This is Parent Process!\n");
    }
    return 0;
}

int main()
{
    PrintMenuOS();
    SetPrompt("MenuOS>>");
    MenuConfig("version","XXX V1.0(Menu program v1.0 inside)",NULL);
    MenuConfig("times","show system times.",times);
    MenuConfig("times-asm","show system times by asm.",times_asm);
    MenuConfig("forks","forks.",forks);
    MenuConfig("executes","executes.",executes);
    MenuConfig("quit","Quit from XXX",Quit);
    ExecuteMenu();
}

$>vi Makefile
-------------
CC_PTHREAD_FLAGS        = -lpthread
CC_FLAGS                = -c 
CC_OUTPUT_FLAGS         = -o
CC                      = gcc
RM                      = rm
RM_FLAGS                = -f

TARGET  =   test
OBJS    =   linktable.o  menu.o test.o

all:    $(OBJS)
    $(CC) $(CC_OUTPUT_FLAGS) $(TARGET) $(OBJS) 
rootfs:
    gcc -o init linktable.c menu.c test.c -m32 -static -lpthread
    mkdir -p ../rootfs/ && cp init ../rootfs/
    find ../rootfs/ | cpio -o -Hnewc |gzip -9 > ../rootfs.img
    qemu -kernel /path/linux-x.y.z/arch/x86/boot/bzImage -initrd /path/rootfs.img
.c.o:
    $(CC) $(CC_FLAGS) $<

clean:
    $(RM) $(RM_FLAGS)  $(OBJS) $(TARGET) *.bak

注意:必须编译i386内核.

通用寄存器
----------------
31        16 15(16bit-高8bit)8 7(16bit-低8bit)0     16-bit   32-bit     
              --------------    -------------
                    AH               AL              AX        EAX      #累加器(accumulator)
                    BH               BL              BX        EBX      #基地址寄存器(base register)
                    CH               CL              CX        ECX      #计数寄存器(count register)
                    DH               DL              DX        EDX      #数据寄存器(data register)
              -----------------------------                                             
                            BP                                 EBP      #堆栈基指针(base pointer)
                            SI                                 ESI      #变址寄存器(index register)
                            DI                                 EDI      #变址寄存器(index register)
                            SP                                 ESP      #堆栈顶指针(stack pointer)
                            
段寄存器
----------------
CS        #代码段寄存器(code segment register),代码段的段值.
DS        #数据段寄存器(data segment register),数据段的段值.
SS        #堆栈段寄存器(stack segment register),堆栈段的段值.
ES        #附加段寄存器(extra segment register),附加段的段值.
FS        #附加段寄存器(extra segment register),附加段的段值.
GS        #附加段寄存器(extra segment register),附加段的段值.

标识寄存器(eflags register)
----------------
31  30  29  28  27  26  25  24  23  22  21  20  19  18  17  16  15  14  13    12   11    10    9    8    7    6  5  4  3  2  1  0
--  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --------   --    --    --   --   --   -- -- -- -- -- -- --     
0   0   0   0   0   0   0   0   0   0   ID  VIP VIF AC  VM  RF  0   NT    IOPL     OF    DF    IF   TF   SF   ZF 0  AF 0  PF 1  CF      

ID Flag                                  ID
Virtual Interrupt Pending                VIP
Virtual Interrupt Flag                   VIF
Alignment Check                          VC
Virtual-8086 Mode                        VM
Resume Flag                              RF
Nested Task                              NT
I/O Privilege Level                      IOPL
Overflow Flag                            OF
Direction Flag                           DF
Interrupt Enable Flag                    IF
Trap Flag                                TF
Sign Flag                                SF
Zero Flag                                ZF
Auxiliary Carry Flag                     AF
Parity Flag                              PF
Carry Flag                               CF

X86_64 Registers
----------------
General-Purpose Registers(GPRs)            64-bit Media and Floating-Point Registers      128-bit Media Registers
63     ~      0                                63     ~      0                             127      ~       0
------- ------- RAX                            --------------- MMX0/FPR0                    -------- ------- XMM0
------- ------- RBX                            --------------- MMX1/FPR1                    -------- ------- XMM1
------- ------- RCX                            --------------- MMX2/FPR2                    -------- ------- XMM2
------- ------- RDX                            --------------- MMX3/FPR3                    -------- ------- XMM3
------- ------- RBP                            --------------- MMX4/FPR4                    -------- ------- XMM4
------- ------- RSI                            --------------- MMX5/FPR5                    -------- ------- XMM5
------- ------- RDI                            --------------- MMX6/FPR6                    -------- ------- XMM6
------- ------- PSP                            --------------- MMX7/FPR7                    -------- ------- XMM7
--------------- R8                                                                          ---------------- XMM8
--------------- R9                            Flags Register                                ---------------- XMM9
--------------- R10                            63     ~      0                              ---------------- XMM10
--------------- R11                           -------- EFLAGS   RFLAGS                      ---------------- XMM11
--------------- R12                                                                         ---------------- XMM12
--------------- R13                           Instruction Pointer                           ---------------- XMM13
--------------- R14                            63     ~      0                              ---------------- XMM14
--------------- R15                           ---------  EIP      RIP                       ---------------- XMM15

mov指令以及寻址方式
----------------
movb         #8bit.
movw         #16bit.
movl         #32bit.
movq         #64bit.

eg.
movl %eax,%edx                    => edx=eax;                            #寄存器寻址(register mode).   
movl $0x123,%edx                  => edx=0x123;                          #立即寻址(immediate).
movl 0x123,%edx                   => edx=*(int32_t*)0x123;               #直接寻址(direct).
movl (%ebx),%edx                  => edx=*(int32_t*)ebx;                 #间接寻址(indirect).
movl 4(%ebx),%edx                 => edx=*(int32_t*)(ebx+4);             #变址寻址(displaced).

注意:b,w,l,q指的是:8bit,16bit,32bit,64bit.

汇编指令(push)
----------------
eg.
pushl %eax       => subl $4,%esp
                    movl %eax,(%esp)
                 
pushq %eax       => subq $8,%esp        #esp,eax这里假设是64bit寄存器.
                    movq %eax,(%esp)

注意:b,w,l,q指的是:8bit,16bit,32bit,64bit.

汇编指令(pop)
----------------
eg.
popl %eax        =>movl (%esp),%eax 
                   addl $4,%esp
                   
注意:b,w,l,q指的是:8bit,16bit,32bit,64bit.                   

汇编指令(call)
----------------
eg.
call 0x12345     =>pushl %eip(*)
                   movl $0x12345,%eip(*)
                   
注意:(*)代表程序员不能直接修改(eip).
                    
汇编指令(ret)
----------------
eg.
ret              =>popl %eip(*)

注意:(*)代表程序员不能直接修改(eip).

汇编例子
----------------
eg.
...
pushl $8
movl %esp,%ebp
subl $4,%esp
movl $8,(%esp)
...

...
pushl $8
movl %esp,%ebp
pushl $8
...


...
pushl $8
movl %esp,%ebp
pushl %esp
pushl $8
addl $4,%esp
popl %esp
...

汇编实操
----------------
$>vi main.c
-------------
int main(int argc,char **argv)
{

    return 0;
}

$>gcc -S -o main.s main.c -m32
$>cat main.s
-------------
    .file    "main.c"
    .text
    .globl    main
    .type    main, @function
main:
.LFB0:
    .cfi_startproc
    pushl    %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    %esp, %ebp
    .cfi_def_cfa_register 5
    movl    $0, %eax
    popl    %ebp
    .cfi_restore 5
    .cfi_def_cfa 4, 4
    ret
    .cfi_endproc
.LFE0:
    .size    main, .-main
    .ident    "GCC: (Debian 4.7.2-5) 4.7.2"
    .section    .note.GNU-stack,"",@progbits
    
    ==>
main:
    pushl    %ebp
    movl    %esp, %ebp
    movl    $0, %eax
    popl    %ebp
    ret
    
注意:所以以"."开头的指令他们都是用于链接的辅助信息,在分析汇编时可以将其去掉.

$>vi hexdump.c
-------------
void v_hexdump(unsigned char *v_first_address, unsigned long v_length) {
    unsigned long i,j,k;
    unsigned char v_binstr[256];

    /**
     * 多行.
     */
    for ( i = 0l; i<v_length; i++ ) {
        if ( 0 == ( i%16 ) ) {                             //行首.            
            sprintf(v_binstr,"%p -",i+v_first_address);    //sprintf(v_binstr,"0x%012x -",i+v_first_address);                                   
            sprintf(v_binstr,"%s %02x",v_binstr,(unsigned char)v_first_address[i]);                  
        } 
        else if ( 15 == ( i%16 ) ) {                       //在"0x000000000000 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"后面输出字符.     
            sprintf(v_binstr,"%s %02x",v_binstr,(unsigned char)v_first_address[i]);                 
            sprintf(v_binstr,"%s  ",v_binstr);                                                               

            for ( j = i-15; j <= i; j++ ) {                                                      
                sprintf(v_binstr,"%s%c",v_binstr,('!'<v_first_address[j]&&v_first_address[j]<='~')?v_first_address[j]:'.'); 
            }
            printf("%s\n",v_binstr);                       //换行并打印字符                               
        } else {
            sprintf(v_binstr,"%s %02x",v_binstr,(unsigned char)v_first_address[i]);
        }
    }

    /*
    *单行或者最后一行.
    */
    if ( 0 != ( i%16 ) ) {
        k = 16 - ( i%16 );

        for ( j = 0; j < k; j++ ) {
            sprintf(v_binstr,"%s   ",v_binstr);
        }

        sprintf(v_binstr,"%s  ",v_binstr);
        k = 16 - k;

        for ( j = i - k; j < i; j++ ) {
            sprintf(v_binstr,"%s%c",v_binstr,('!'<v_first_address[j]&&v_first_address[j]<='~')?v_first_address[j]:'.');
        }
        printf("%s\n",v_binstr);                           //换行并打印字符
    }
}

$>gcc -S -o hexdump.s hexdump.c -m32
$>cat hexdump.s
-------------
    .file    "hexdump.c"
    .section    .rodata
.LC0:
    .string    "%p -"
.LC1:
    .string    "%s %02x"
.LC2:
    .string    "%s  "
.LC3:
    .string    "%s%c"
.LC4:
    .string    "%s   "
    .text
    .globl    v_hexdump
    .type    v_hexdump, @function
v_hexdump:
.LFB0:
    .cfi_startproc
    pushl    %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    %esp, %ebp
    .cfi_def_cfa_register 5
    subl    $296, %esp
    movl    $0, -12(%ebp)
    jmp    .L2
.L10:
    movl    -12(%ebp), %eax
    andl    $15, %eax
    testl    %eax, %eax
    jne    .L3
    movl    -12(%ebp), %eax
    movl    8(%ebp), %edx
    addl    %edx, %eax
    movl    %eax, 8(%esp)
    movl    $.LC0, 4(%esp)
    leal    -276(%ebp), %eax
    movl    %eax, (%esp)
    call    sprintf
    movl    -12(%ebp), %eax
    movl    8(%ebp), %edx
    addl    %edx, %eax
    movzbl    (%eax), %eax
    movzbl    %al, %eax
    movl    %eax, 12(%esp)
    leal    -276(%ebp), %eax
    movl    %eax, 8(%esp)
    movl    $.LC1, 4(%esp)
    leal    -276(%ebp), %eax
    movl    %eax, (%esp)
    call    sprintf
    jmp    .L4
.L3:
    movl    -12(%ebp), %eax
    andl    $15, %eax
    cmpl    $15, %eax
    jne    .L5
    movl    -12(%ebp), %eax
    movl    8(%ebp), %edx
    addl    %edx, %eax
    movzbl    (%eax), %eax
    movzbl    %al, %eax
    movl    %eax, 12(%esp)
    leal    -276(%ebp), %eax
    movl    %eax, 8(%esp)
    movl    $.LC1, 4(%esp)
    leal    -276(%ebp), %eax
    movl    %eax, (%esp)
    call    sprintf
    leal    -276(%ebp), %eax
    movl    %eax, 8(%esp)
    movl    $.LC2, 4(%esp)
    leal    -276(%ebp), %eax
    movl    %eax, (%esp)
    call    sprintf
    movl    -12(%ebp), %eax
    subl    $15, %eax
    movl    %eax, -16(%ebp)
    jmp    .L6
.L9:
    movl    -16(%ebp), %eax
    movl    8(%ebp), %edx
    addl    %edx, %eax
    movzbl    (%eax), %eax
    cmpb    $33, %al
    jbe    .L7
    movl    -16(%ebp), %eax
    movl    8(%ebp), %edx
    addl    %edx, %eax
    movzbl    (%eax), %eax
    cmpb    $126, %al
    ja    .L7
    movl    -16(%ebp), %eax
    movl    8(%ebp), %edx
    addl    %edx, %eax
    movzbl    (%eax), %eax
    movzbl    %al, %eax
    jmp    .L8
.L7:
    movl    $46, %eax
.L8:
    movl    %eax, 12(%esp)
    leal    -276(%ebp), %eax
    movl    %eax, 8(%esp)
    movl    $.LC3, 4(%esp)
    leal    -276(%ebp), %eax
    movl    %eax, (%esp)
    call    sprintf
    addl    $1, -16(%ebp)
.L6:
    movl    -16(%ebp), %eax
    cmpl    -12(%ebp), %eax
    jbe    .L9
    leal    -276(%ebp), %eax
    movl    %eax, (%esp)
    call    puts
    jmp    .L4
.L5:
    movl    -12(%ebp), %eax
    movl    8(%ebp), %edx
    addl    %edx, %eax
    movzbl    (%eax), %eax
    movzbl    %al, %eax
    movl    %eax, 12(%esp)
    leal    -276(%ebp), %eax
    movl    %eax, 8(%esp)
    movl    $.LC1, 4(%esp)
    leal    -276(%ebp), %eax
    movl    %eax, (%esp)
    call    sprintf
.L4:
    addl    $1, -12(%ebp)
.L2:
    movl    -12(%ebp), %eax
    cmpl    12(%ebp), %eax
    jb    .L10
    movl    -12(%ebp), %eax
    andl    $15, %eax
    testl    %eax, %eax
    je    .L1
    movl    -12(%ebp), %eax
    movl    %eax, %edx
    andl    $15, %edx
    movl    $16, %eax
    subl    %edx, %eax
    movl    %eax, -20(%ebp)
    movl    $0, -16(%ebp)
    jmp    .L12
.L13:
    leal    -276(%ebp), %eax
    movl    %eax, 8(%esp)
    movl    $.LC4, 4(%esp)
    leal    -276(%ebp), %eax
    movl    %eax, (%esp)
    call    sprintf
    addl    $1, -16(%ebp)
.L12:
    movl    -16(%ebp), %eax
    cmpl    -20(%ebp), %eax
    jb    .L13
    leal    -276(%ebp), %eax
    movl    %eax, 8(%esp)
    movl    $.LC2, 4(%esp)
    leal    -276(%ebp), %eax
    movl    %eax, (%esp)
    call    sprintf
    movl    $16, %eax
    subl    -20(%ebp), %eax
    movl    %eax, -20(%ebp)
    movl    -20(%ebp), %eax
    movl    -12(%ebp), %edx
    movl    %edx, %ecx
    subl    %eax, %ecx
    movl    %ecx, %eax
    movl    %eax, -16(%ebp)
    jmp    .L14
.L17:
    movl    -16(%ebp), %eax
    movl    8(%ebp), %edx
    addl    %edx, %eax
    movzbl    (%eax), %eax
    cmpb    $33, %al
    jbe    .L15
    movl    -16(%ebp), %eax
    movl    8(%ebp), %edx
    addl    %edx, %eax
    movzbl    (%eax), %eax
    cmpb    $126, %al
    ja    .L15
    movl    -16(%ebp), %eax
    movl    8(%ebp), %edx
    addl    %edx, %eax
    movzbl    (%eax), %eax
    movzbl    %al, %eax
    jmp    .L16
.L15:
    movl    $46, %eax
.L16:
    movl    %eax, 12(%esp)
    leal    -276(%ebp), %eax
    movl    %eax, 8(%esp)
    movl    $.LC3, 4(%esp)
    leal    -276(%ebp), %eax
    movl    %eax, (%esp)
    call    sprintf
    addl    $1, -16(%ebp)
.L14:
    movl    -16(%ebp), %eax
    cmpl    -12(%ebp), %eax
    jb    .L17
    leal    -276(%ebp), %eax
    movl    %eax, (%esp)
    call    puts
.L1:
    leave
    .cfi_restore 5
    .cfi_def_cfa 4, 4
    ret
    .cfi_endproc
.LFE0:
    .size    v_hexdump, .-v_hexdump
    .ident    "GCC: (Debian 4.7.2-5) 4.7.2"
    .section    .note.GNU-stack,"",@progbits

$>vi hexdump.c
-------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void v_hexdump(unsigned char *v_first_address, unsigned long v_length) {
    unsigned long i,j,k;
    unsigned char v_binstr[256];

    /**
     * 多行.
     */
    for ( i = 0l; i<v_length; i++ ) {
        if ( 0 == ( i%16 ) ) {                             //行首.            
            sprintf(v_binstr,"%p -",i+v_first_address);    //sprintf(v_binstr,"0x%012x -",i+v_first_address);                                   
            sprintf(v_binstr,"%s %02x",v_binstr,(unsigned char)v_first_address[i]);                  
        } 
        else if ( 15 == ( i%16 ) ) {                       //在"0x000000000000 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"后面输出字符.     
            sprintf(v_binstr,"%s %02x",v_binstr,(unsigned char)v_first_address[i]);                 
            sprintf(v_binstr,"%s  ",v_binstr);                                                               

            for ( j = i-15; j <= i; j++ ) {                                                      
                sprintf(v_binstr,"%s%c",v_binstr,('!'<v_first_address[j]&&v_first_address[j]<='~')?v_first_address[j]:'.'); 
            }
            printf("%s\n",v_binstr);                       //换行并打印字符                               
        } else {
            sprintf(v_binstr,"%s %02x",v_binstr,(unsigned char)v_first_address[i]);
        }
    }

    /*
    *单行或者最后一行.
    */
    if ( 0 != ( i%16 ) ) {
        k = 16 - ( i%16 );

        for ( j = 0; j < k; j++ ) {
            sprintf(v_binstr,"%s   ",v_binstr);
        }

        sprintf(v_binstr,"%s  ",v_binstr);
        k = 16 - k;

        for ( j = i - k; j < i; j++ ) {
            sprintf(v_binstr,"%s%c",v_binstr,('!'<v_first_address[j]&&v_first_address[j]<='~')?v_first_address[j]:'.');
        }
        printf("%s\n",v_binstr);                           //换行并打印字符
    }
}

int main(int argc,char **argv)
{
    unsigned int i=0;
    v_hexdump((char *)&i,sizeof(i));
    return 0;
}

$>gcc -S -o hexdump.s hexdump.c -m32
$>cat hexdump.s
-------------
    .file    "hexdump.c"
    .section    .rodata
.LC0:
    .string    "%p -"
.LC1:
    .string    "%s %02x"
.LC2:
    .string    "%s  "
.LC3:
    .string    "%s%c"
.LC4:
    .string    "%s   "
    .text
    .globl    v_hexdump
    .type    v_hexdump, @function
v_hexdump:
.LFB0:
    .cfi_startproc
    pushl    %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    %esp, %ebp
    .cfi_def_cfa_register 5
    subl    $296, %esp
    movl    $0, -12(%ebp)
    jmp    .L2
.L10:
    movl    -12(%ebp), %eax
    andl    $15, %eax
    testl    %eax, %eax
    jne    .L3
    movl    -12(%ebp), %eax
    movl    8(%ebp), %edx
    addl    %edx, %eax
    movl    %eax, 8(%esp)
    movl    $.LC0, 4(%esp)
    leal    -276(%ebp), %eax
    movl    %eax, (%esp)
    call    sprintf
    movl    -12(%ebp), %eax
    movl    8(%ebp), %edx
    addl    %edx, %eax
    movzbl    (%eax), %eax
    movzbl    %al, %eax
    movl    %eax, 12(%esp)
    leal    -276(%ebp), %eax
    movl    %eax, 8(%esp)
    movl    $.LC1, 4(%esp)
    leal    -276(%ebp), %eax
    movl    %eax, (%esp)
    call    sprintf
    jmp    .L4
.L3:
    movl    -12(%ebp), %eax
    andl    $15, %eax
    cmpl    $15, %eax
    jne    .L5
    movl    -12(%ebp), %eax
    movl    8(%ebp), %edx
    addl    %edx, %eax
    movzbl    (%eax), %eax
    movzbl    %al, %eax
    movl    %eax, 12(%esp)
    leal    -276(%ebp), %eax
    movl    %eax, 8(%esp)
    movl    $.LC1, 4(%esp)
    leal    -276(%ebp), %eax
    movl    %eax, (%esp)
    call    sprintf
    leal    -276(%ebp), %eax
    movl    %eax, 8(%esp)
    movl    $.LC2, 4(%esp)
    leal    -276(%ebp), %eax
    movl    %eax, (%esp)
    call    sprintf
    movl    -12(%ebp), %eax
    subl    $15, %eax
    movl    %eax, -16(%ebp)
    jmp    .L6
.L9:
    movl    -16(%ebp), %eax
    movl    8(%ebp), %edx
    addl    %edx, %eax
    movzbl    (%eax), %eax
    cmpb    $33, %al
    jbe    .L7
    movl    -16(%ebp), %eax
    movl    8(%ebp), %edx
    addl    %edx, %eax
    movzbl    (%eax), %eax
    cmpb    $126, %al
    ja    .L7
    movl    -16(%ebp), %eax
    movl    8(%ebp), %edx
    addl    %edx, %eax
    movzbl    (%eax), %eax
    movzbl    %al, %eax
    jmp    .L8
.L7:
    movl    $46, %eax
.L8:
    movl    %eax, 12(%esp)
    leal    -276(%ebp), %eax
    movl    %eax, 8(%esp)
    movl    $.LC3, 4(%esp)
    leal    -276(%ebp), %eax
    movl    %eax, (%esp)
    call    sprintf
    addl    $1, -16(%ebp)
.L6:
    movl    -16(%ebp), %eax
    cmpl    -12(%ebp), %eax
    jbe    .L9
    leal    -276(%ebp), %eax
    movl    %eax, (%esp)
    call    puts
    jmp    .L4
.L5:
    movl    -12(%ebp), %eax
    movl    8(%ebp), %edx
    addl    %edx, %eax
    movzbl    (%eax), %eax
    movzbl    %al, %eax
    movl    %eax, 12(%esp)
    leal    -276(%ebp), %eax
    movl    %eax, 8(%esp)
    movl    $.LC1, 4(%esp)
    leal    -276(%ebp), %eax
    movl    %eax, (%esp)
    call    sprintf
.L4:
    addl    $1, -12(%ebp)
.L2:
    movl    -12(%ebp), %eax
    cmpl    12(%ebp), %eax
    jb    .L10
    movl    -12(%ebp), %eax
    andl    $15, %eax
    testl    %eax, %eax
    je    .L1
    movl    -12(%ebp), %eax
    movl    %eax, %edx
    andl    $15, %edx
    movl    $16, %eax
    subl    %edx, %eax
    movl    %eax, -20(%ebp)
    movl    $0, -16(%ebp)
    jmp    .L12
.L13:
    leal    -276(%ebp), %eax
    movl    %eax, 8(%esp)
    movl    $.LC4, 4(%esp)
    leal    -276(%ebp), %eax
    movl    %eax, (%esp)
    call    sprintf
    addl    $1, -16(%ebp)
.L12:
    movl    -16(%ebp), %eax
    cmpl    -20(%ebp), %eax
    jb    .L13
    leal    -276(%ebp), %eax
    movl    %eax, 8(%esp)
    movl    $.LC2, 4(%esp)
    leal    -276(%ebp), %eax
    movl    %eax, (%esp)
    call    sprintf
    movl    $16, %eax
    subl    -20(%ebp), %eax
    movl    %eax, -20(%ebp)
    movl    -20(%ebp), %eax
    movl    -12(%ebp), %edx
    movl    %edx, %ecx
    subl    %eax, %ecx
    movl    %ecx, %eax
    movl    %eax, -16(%ebp)
    jmp    .L14
.L17:
    movl    -16(%ebp), %eax
    movl    8(%ebp), %edx
    addl    %edx, %eax
    movzbl    (%eax), %eax
    cmpb    $33, %al
    jbe    .L15
    movl    -16(%ebp), %eax
    movl    8(%ebp), %edx
    addl    %edx, %eax
    movzbl    (%eax), %eax
    cmpb    $126, %al
    ja    .L15
    movl    -16(%ebp), %eax
    movl    8(%ebp), %edx
    addl    %edx, %eax
    movzbl    (%eax), %eax
    movzbl    %al, %eax
    jmp    .L16
.L15:
    movl    $46, %eax
.L16:
    movl    %eax, 12(%esp)
    leal    -276(%ebp), %eax
    movl    %eax, 8(%esp)
    movl    $.LC3, 4(%esp)
    leal    -276(%ebp), %eax
    movl    %eax, (%esp)
    call    sprintf
    addl    $1, -16(%ebp)
.L14:
    movl    -16(%ebp), %eax
    cmpl    -12(%ebp), %eax
    jb    .L17
    leal    -276(%ebp), %eax
    movl    %eax, (%esp)
    call    puts
.L1:
    leave
    .cfi_restore 5
    .cfi_def_cfa 4, 4
    ret
    .cfi_endproc
.LFE0:
    .size    v_hexdump, .-v_hexdump
    .globl    main
    .type    main, @function
main:
.LFB1:
    .cfi_startproc
    pushl    %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    %esp, %ebp
    .cfi_def_cfa_register 5
    andl    $-16, %esp
    subl    $32, %esp
    movl    $0, 28(%esp)
    movl    $4, 4(%esp)
    leal    28(%esp), %eax
    movl    %eax, (%esp)
    call    v_hexdump
    movl    $0, %eax
    leave
    .cfi_restore 5
    .cfi_def_cfa 4, 4
    ret
    .cfi_endproc
.LFE1:
    .size    main, .-main
    .ident    "GCC: (Debian 4.7.2-5) 4.7.2"
    .section    .note.GNU-stack,"",@progbits

sys_time系统调用
----------------
b sys_time 
b system_call

fork系统调用
----------------
b sys_clone
b do_fork                    #gdb调试的时候会停在这.
b dup_task_struct
b copy_process               #创建进程内容的主要代码.
b copy_thread                #"/path/linux-x.y.z/kernel/process_32.c".
b ret_from_fork

注意:主要代码在"/path/linux-x.y.z/kernel/fork.c".

execve系统调用
----------------
b sys_execve
b do_execve
b do_execve_common
b do_open_exec               #加载执行文件.
b exec_binprm                #关键地方,可执行文件的处理过程.
b search_binary_handler      #寻找可执行文件的处理函数.
b list_for_each_entry
b load_elf_binary            #"/path/linux-x.y.z/fs/binfmt_elf.c".
b load_elf_library
b schedule                   #选择一个新的进程来运行,"/path/linux-x.y.z/kernel/sched/core.c".
b pick_next_task             #进程调度算法都封装在这个函数的内部.
b context_switch
b switch_to                  #"/path/linux-x.y.z/arch/x86/include/asm/switch_to.h".

注意:ELF可执行文件总是被默认映射到0x8048000这个地址上.

寄存器结构名称
----------------
struct pt_regs{
  ...
}

系统调用的总控程序
----------------
entry_32.S
or
entry_64.S

内核操作系统的三大功能
----------------
1.进程管理(核心)
2.内存管理
3.文件系统

注意:进程控制块(PCB),结构体(struct task_struct);位置在"/path/linux-x.y.z/include/linux/sched.h".

执行文件生成过程
----------------
$>gcc -E -o xx-name.cpp xx-name.c -m32               #预处理,step.1.
$>gcc -x cpp-output -S -o xx-name.s xx-name.cpp -m32 #step.2.
$>gcc -x assembler -c xx-name.s -o xx-name.o -m32    #step.3.
$>gcc -o xx-name xx-name.o -m32                      #step.4.
$>gcc -o xx-name.static xx-name.o -m32 -static       #step.4.

内核Makefile
----------------
$>make ARCH=x86_64        #实质上是"/path/linux-x.y.z/arch/x86/configs/x86_64_defconfig"文件.
$>make ARCH=x86           #实质上是"/path/linux-x.y.z/arch/x86/configs/i386_defconfig"文件.

交叉编译内核
----------------
$>make -jn ARCH=arm64/arm/x86_64/x86 CROSS_COMPILE=xxx-gnu- deconfig    #step.1
$>make -jn ARCH=arm64/arm/x86_64/x86 CROSS_COMPILE=xxx-gnu-             #step.2
$>sudo make headers_install                          
$>sudo make modules_install

在(qemu)虚拟机中运行新的内核
----------------
$>mkdir -p /path/initrd && cp /home/vsftpd/busybox-1.20.0.zip /path/initrd                                                                                           #step.1,构建内存文件.
$>cd /path/initrd && unzip busybox-1.20.0.zip
$>cd  /path/initrd/busybox-1.20.0

$>make menuconfig                                                                                                                                                    #必须选中"Build BusyBox as a static binary (no shared libs) ",Busybox Settings--->Build Options--->[*] Build BusyBox as a static binary (no shared libs). 
$>make -j4 && make install
$>cd .. && mkdir -p initramfs
or
$>make install CONFIG_PREFIX=/path/initrd/initramfs

$>cd initramfs && mkdir -pv {bin,sbin,etc,tmp,dev,proc,sys,usr/{bin,sbin}}
$>cp -av ../busybox-1.20.0/_install/* .
$>mknod dev/console c 5 1
$>mknod dev/null c 1 3
$>vi init
-------------
#!/bin/sh 

mount -t proc proc /proc 
mount -t sysfs proc /sys

$>chmod +x init
$>sudo chown -R root:root *
$>find . -print0 | cpio --null -ov --format=newc | gzip -9 > /path/initrd_$(ARCH).gz
or
$>find ./initramfs/ | cpio -o -Hnewc |gzip -9 > /path/initrd_$(ARCH).gz

$>date -s 20180630                                                                                                                                                     #step.2,这里必须进行设置否则会导致编译不了.

$>make ARCH=x86 allyesconfig                                                                                                                                           #step.3,编译内核.
$>make ARCH=x86 -j4
or
$>make -j4 i386_defconfig
$>make -j4
or
$>make -j4 x86_64_defconfig
$>make -j4

$>qemu-system-x86_64 -m 512M -serial stdio -kernel /path/linux-x.y.z/arch/x86/boot/bzImage -initrd /path/initrd_$(ARCH).gz -append "init=/bin/sh ignore_loglevel"      #step.4,运行.

注意:以上内容实验没有成功,但是具有参考意义.

内核编译
----------------
inst 
------------
$>apt-get install git fakeroot build-essential ncurses-dev xz-utils libssl-dev bc flex libelf-dev bison qemu 

编译与调试
------------
编译内核的步骤
----------
$>make x86_64_defconfig                                                                                 #step.1

注意:每次执行这条命令时都会重新生成"linux-x.y.z/.config",".config"的生成在"linux-x.y.z/Makefile"中的["config/%config"]标记中生成的(config-targets=1);实际上对应的是"linux-x.y.z\arch\$x\configs\$y_defconfig"下的配置文件.

$>vi linux-x.y.z/.config                                                                                #step.2
----------
CONFIG_DEBUG_INFO=y
CONFIG_FRAME_POINTER=y
CONFIG_DEBUG_KERNEL=y
CONFIG_DEBUG_FS=y
CONFIG_SLUB_DEBUG_ON=y
CONFIG_DMA_API_DEBUG=y

注意:为了避免每次都修改.config配置文件,可以直接修改"linux-x.y.z\arch\$x\configs\$y_defconfig";将以上内容直接粘贴到"linux-x.y.z\arch\$x\configs\$y_defconfig"即可.["CONFIG_FRAME_POINTER"]还是需要修改"linux-x.y.z/.config"进行手动添加;经过测试通过,不用每次都修改该文件.

$>vi linux-x.y.z/Makefile                                                                               #step.3
----------
KBUILD_HOSTCFLAGS   = -v -g -Wall -Wmissing-prototypes -Wstrict-prototypes -O0 -fomit-frame-pointer
KBUILD_HOSTCXXFLAGS = -v -g -O0
...
ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
KBUILD_CFLAGS    += -O0 $(call cc-disable-warning,maybe-uninitialized,)
else
ifdef CONFIG_PROFILE_ALL_BRANCHES
KBUILD_CFLAGS    += -O0 $(call cc-disable-warning,maybe-uninitialized,)
else
KBUILD_CFLAGS   += -O0
endif
endif
...

$>/usr/bin/qemu-system-x86_64 -no-quit -S -s -curses -kernel /path/linux-x.y.z/arch/x86/boot/bzImage     #step.4
$>cd /path/linux-x.y.z && gdb vmlinux                                                                    #step.5
gdb>target remote 127.0.0.1:1234
gdb>b start_kernel                                                                                       #将断点打在start_kernel.
gdb>b ...                                                                                                #打断点.
gdb>set args ...                                                                                         #设置运行参数.
gdb>c or s                                                                                               #继续(continue)运行.
gdb>bt  

内核调试脚本
----------
$>mkdir /path/bin
$>vi ~/.bashrc
--------
export PATH=$PATH:/path/bin

$>vi /path/bin/kterminal.sh                                                                              #step.1
--------
#!/bin/bash

KDIR=/path/linux-x.y.z
#####打开一个终端,一个qemu窗口#####
cd $KDIR && gnome-terminal --hide-menubar  --title="Terminal" --geometry=100X85+85+85 &
/usr/bin/qemu-system-x86_64 -no-quit -S -s -curses -kernel $KDIR/arch/x86/boot/bzImage 

$>vi /path/bin/r.sh                                                                                      #step.2
--------
#!/bin/bash

/usr/bin/qemu-system-x86_64 -no-quit -S -s -curses -kernel /path/linux-x.y.z/arch/x86/boot/bzImage 

$>vi /path/bin/kdebug.sh                                                                                 #step.3
--------
#!/bin/bash

#####启动gdb的shell脚本文件#####
mkdir -p /path/debug
touch /path/debug/khistory
touch /path/debug/kcfg
touch /path/debug/log.txt
touch /path/debug/breakpoints

gdb -x /path/debug/kcfg /path/linux-x.y.z/vmlinux                                                        #注意这里必须使用绝对路径.

$>vi /path/debug/kcfg
--------
#####gdb配置文件#####
set confirm off
set pagination off
set print elements 0
set print array-indexes on
set print pretty on
set history filename /path/debug/khistory                   #注意这里必须使用绝对路径.
set history save on
set logging file /path/debug/log.txt                        #注意这里必须使用绝对路径.
set logging on
set logging overwrite on

source /path/debug/breakpoints                              #注意这里必须使用绝对路径.
python sys.path.append("/usr/share/gcc-4.7/python/");
target remote 127.0.0.1:1234

#breakpoints
b start_kernel
display $pc
display /x $cs

define rr
  target remote 127.0.0.1:1234
  c
end

define xx-cmd                                                #自定义命令.
  ...
  yy-context
  ...
end


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

胡致云

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值