(3) die函数中调用在die函数中取得thread_info结构体的地址。

struct thread_info *thread = current_thread_info();

static inline struct thread_info *current_thread_info(void){
  register unsigned long sp asm ("sp");
  return (struct thread_info *)(sp &~(THREAD_SIZE - 1));
}

Sp: 0xc07e9c28通过current_thread_info得到 thread_info的地址

(0xc07e9c28 &0xffffe000) = 0xC07E8000thread_info的地址,也就是栈底的地址)

(4)下面的打印信息在__die函数中打印

Internal error: Oops: 1 [#1]
last sysfs file: /sys/devices/form/tpm/cfg_l2/l2_rule_add
Modules linked in: splic mmp(P)
CPU: 0    Tainted: P            (2.6.32.11 #42)
PC is at dev_get_by_flags+0xfc/0x140
LR is at dev_get_by_flags+0xe8/0x140
pc : [<c06bee24>]    lr : [<c06bee10>]    psr: 20000013
sp : c07e9c28  ip : 00000000  fp : c07e9c64
r10: c6bcc560  r9 : c646a220  r8 : c66a0000
r7 : c6a00000  r6 : c0204e56  r5 : 30687461  r4 : 30687461
r3 : 00000000  r2 : 00000010  r1 : c0204e56  r0 : ffffffff
Flags: nzCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment kernel
Control: 0005397f  Table: 065a4000  DAC: 00000017
Process swapper (pid: 0, stack limit = 0xc07e8270)
Stack: (0xc07e9c28 to 0xc07ea000)

函数的调用关系:die("Oops", regs, fsr);---à__die(str, err, thread, regs);

下面是__die函数的定义:

static void __die(const char *str, int err, struct thread_info *thread, struct pt_regs *regs){
  struct task_struct *tsk = thread->task;
  static int die_counter;
  /*Internal error: Oops: 1 [#1]*/
  printk(KERN_EMERG "Internal error: %s: %x [#%d]" S_PREEMPT S_SMP "
",
    str, err, ++die_counter);
  /*last sysfs file: /sys/devices/form/tpm/cfg_l2/l2_rule_add*/
  sysfs_printk_last_file();
  /*内核中加载的模块信息Modules linked in: splic mmp(P) */
  print_modules();
  /*打印寄存器信息*/
  __show_regs(regs);
  /*Process swapper (pid: 0, stack limit = 0xc07e8270) tsk->comm  task_struct结构体中的comm表示的是除去路径后的可执行文件名称,这里的swapper为idle进程,进程号为0,创建内核进程init;其中stack limit = 0xc07e8270  指向thread_info的结束地址。*/
  printk(KERN_EMERG "Process %.*s (pid: %d, stack limit = 0x%p)
",
    TASK_COMM_LEN, tsk->comm, task_pid_nr(tsk), thread + 1);
  /* dump_mem 函数打印从栈顶到当前sp之间的内容*/
  if (!user_mode(regs) || in_interrupt()) {
    dump_mem(KERN_EMERG, "Stack: ", regs->ARM_sp, THREAD_SIZE + (unsigned long)task_stack_page(tsk));
    dump_backtrace(regs, tsk);
    dump_instr(KERN_EMERG, regs);
  }
}

在上面的函数中,主要使用了thread_info,task_struct,sp之间的指向关系。task_struct结构体的成员stack是栈底,也是对应thread_info结构体的地址。堆栈数据是从栈底+8K的地方开始向下存的。SP指向的是当前的栈顶。(unsigned long)task_stack_page(tsk),

#define task_stack_page(task)((task)->stack) ,该宏根据task_struct得到栈底,也就是thread_info地址。

#define task_thread_info(task) ((struct thread_info *)(task)->stack),该宏根据task_struct得到thread_info指针。

5)dump_backtrace函数

该函数用于打印函数的调用关系。Fp为帧指针,用于追溯程序的方式,方向跟踪调用函数。该函数主要是fp进行检查,看看能否进行backtrace,如果可以就调用汇编的c_backtrace,在arch/arm/lib/backtrace.S函数中。

static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
{
  unsigned int fp, mode;
  int ok = 1;
 
  printk("Backtrace: ");
  if (!tsk)
    tsk = current;
 
  if (regs) {
    fp = regs->ARM_fp;
    mode = processor_mode(regs);
  } else if (tsk != current) {
    fp = thread_saved_fp(tsk);
    mode = 0x10;
  } else {
    asm("mov %0, fp" : "=r" (fp) : : "cc");
    mode = 0x10;
  }
 
  if (!fp) {
    printk("no frame pointer");
    ok = 0;
  } else if (verify_stack(fp)) {
    printk("invalid frame pointer 0x%08x", fp);
    ok = 0;
  } else if (fp <(unsigned long)end_of_stack(tsk))
    printk("frame pointer underflow");
    printk("
");
    if (ok)
      c_backtrace(fp, mode);
}

6)dump_instr

根据PC指针和指令mode, 打印出当前执行的指令码

Code: 0a000008 e5944000 e2545000 0a000005 (e4153010)

内核中函数的调用关系

原文链接:http://blog.chinaunix.net/uid-20788636-id-4377271.html


相关内容