Linux核心堆棧調用實現分析-save_stack_trace,printstacktrace

來源:互聯網
上載者:User

Linux核心堆棧調用實現分析-save_stack_trace,printstacktrace
1 核心線程

核心為每個線程分配8K的棧空間, 在每個堆棧的頂部放著struct thread_info 結構體,用來儲存線程相關資訊.

其中有幾個重要變數:

Preempt_count :

此變數分為四部分

0-7bit :當前進程是否能搶佔的標誌

8-15bit:softirq  使能標誌

16-23bit :hardirq 使能標誌

24bit:PREEMPT_ACTIVE標誌位(原子上下文標誌位??)

Task:  進程相關的結構,包含更加豐富的資訊

Cpu_context :cpu 寄存器值,這個應該是當前進程被切換時,保留下來的線程執行情境.

struct thread_info {

    unsignedlong     flags;     /* low level flags */

    int        preempt_count;    /* 0 => preemptable, <0 => bug */

    mm_segment_t      addr_limit;   /* address limit */

    structtask_struct   *task;     /* main task structure */

    __u32         cpu;       /*cpu */

    structcpu_context_save  cpu_context;  /* cpu context */

 ……………………….

}

擷取當前線程/進程

只需要獲得當前sp指標,然後進行8k位元組對齊即可找到thread_info結構

register unsignedlong sp asm ("sp");

return (structthread_info *)(sp & ~(THREAD_SIZE - 1));

核心提供的相關函數結構

 static inline struct thread_info*current_thread_info(void)

     以及current宏用於擷取當前進程結構體.

c 語言中擷取cpsr寄存器

static inline unsigned longarch_local_cpsr_save(void)

{

   unsignedlong flags ;

   asmvolatile( "   mrs %0, cpsr   @ arch_local_irq_save\n"

      :: "r" (flags): "memory", "cc");

   returnflags;

}

2 函數調用時stack frame

每一個進程都有自己的棧。考慮進程執行時發生函數調用的情境,母函數和子函數使用的是同一個棧,在通常的情況下,並不需要區分母函數和子函數分別使用了棧的哪個部分。但是,當需要在執行過程中對函數調用進行backtrace的時候,這一資訊就很重要了。

簡單的說,stack frame就是一個函數所使用的stack的一部分,所有函數的stack frame串起來就組成了一個完整的棧。stack frame的兩個邊界分別由FP和SP來限定。

通過FP指標就可以找出所有的backtrace過程

在程式執行過程中(通常是發生了某種意外情況而需要進行調試),通過SP和FP所限定的 stackframe,就可以得到母函數的SP和FP,從而得到母函數的stack frame(PC,LR,SP,FP會在函數調用的第一時間壓棧),以此追溯,即可得到所有函數的調用順序。

要核心支援FP指標必須開啟CONFIG_FRAME_POINTER配置

3核心save_stack_trace分析

voidsave_stack_trace(struct stack_trace *trace)

{

save_stack_trace_tsk(current, trace);

}

接著分析:

voidsave_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)

{

struct stack_trace_data data;

struct stackframe frame;

 

data.trace = trace;

data.skip = trace->skip;//設定需要忽視的調用級數,一般設定為0

 

if (tsk != current) {

#ifdefCONFIG_SMP

           /*

            * What guarantees do we have here that 'tsk'is not

            * running on another CPU?  For now, ignore it as we

            * can't guarantee we won't explode.

            */

//如果不是儲存當前cpu上的當前進程,那麼是很難確定tsk進程寄存器的值的,

也許時刻都在變化.

           if (trace->nr_entries <trace->max_entries)

                    trace->entries[trace->nr_entries++]= ULONG_MAX;

           return;

#else //在單cpu時,tsk進程已經被切換,可以追溯backtrace

           data.no_sched_functions = 1;

           frame.fp = thread_saved_fp(tsk);

           frame.sp = thread_saved_sp(tsk);

           frame.lr = 0;              /* recovered from the stack */

           frame.pc = thread_saved_pc(tsk);

#endif

} else {

           register unsigned long current_sp asm("sp");//通過sp擷取當前堆棧指標

   //__builtin_frame_address(0)返回當前函數的FP指標

 //__builtin_return_address(0)返回當前函數的返回地址(LR)

           data.no_sched_functions = 0;

           frame.fp = (unsignedlong)__builtin_frame_address(0);

           frame.sp = current_sp;

           frame.lr = (unsignedlong)__builtin_return_address(0);

           frame.pc = (unsignedlong)save_stack_trace_tsk;//通過函數名擷取到當前pc

}

 

walk_stackframe(&frame, save_trace,&data);//進行堆棧遍曆

if (trace->nr_entries <trace->max_entries)

           trace->entries[trace->nr_entries++]= ULONG_MAX;

}

其中save_trace主要儲存當前pc到數組中.

staticint save_trace(struct stackframe *frame, void *d)

{

struct stack_trace_data *data = d;

struct stack_trace *trace = data->trace;

unsigned long addr = frame->pc;

if (data->no_sched_functions &&in_sched_functions(addr))

           return 0;

if (data->skip) {//如果有設定skip,則會跳過當前調用

           data->skip--;

           return 0;

}

trace->entries[trace->nr_entries++] =addr;//儲存當前pc

return trace->nr_entries >=trace->max_entries;

}

接著分析walk_stackframe函數

void notrace walk_stackframe(struct stackframe *frame,

               int (*fn)(struct stackframe *, void *), void *data)

{

while (1) {

           int ret;

 

           if (fn(frame, data))//調用save_trace儲存當前pc

                    break;

           ret = unwind_frame(frame);//把FP指標移到上一個函數

           if (ret < 0)

                    break;

}

}


 

intnotrace unwind_frame(struct stackframe *frame)

{

unsigned long high, low;

unsigned long fp = frame->fp;

 

/* only go to a higher address on the stack */

low = frame->sp;//當前堆棧末端

high = ALIGN(low, THREAD_SIZE);//當前堆棧頂端

 

/* check current frame pointer is within bounds*/

if (fp < low + 12 || fp > high - 4)

           return -EINVAL;

 

/* restore the registers from the stack frame*/

由上面的堆棧圖可知,這幾個指標在堆棧上的存放順序為

Pc,lr,sp,fp

frame->fp = *(unsigned long *)(fp - 12);

frame->sp = *(unsigned long *)(fp - 8);

frame->pc = *(unsigned long *)(fp - 4);

return 0;

}

 3.1 擷取stack執行個體

 voidaee_get_traces(char *msg)

{

         structstack_trace trace;

         inti;

         intoffset;

         if(trace_entry_ptr == NULL)

                   return;

         memset(trace_entry_ptr,0, MAX_STACK_TRACE_DEPTH * 4);

         trace.entries= trace_entry_ptr;

         /*savebacktraces */

         trace.nr_entries= 0;

         trace.max_entries= 32;//32級調用

         trace.skip= 0;

         save_stack_trace_tsk(current,&trace);

         for(i = 0; i < trace.nr_entries; i++) {//current

                   offset= strlen(msg);

                   //根據pc,通過%pf , %pf就可以列印出函數名

                   snprintf(msg+ offset, KERNEL_REPORT_LENGTH - offset, "[<%p>]%pS\n",

                             (void *)trace.entries[i], (void*)trace.entries[i]);

         }

}


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.