Linux kernel stack Call implementation analysis

Source: Internet
Author: User

1 Kernel threads

The kernel allocates 8K of stack space for each thread , with a struct thread_info structure at the top of each stack to hold thread-related information.

There are several important variables:

Preempt_count:

This variable is divided into four parts

0-7bit : Flag of whether the current process can be preempted

8-15BIT:SOFTIRQ Enable Flag

16-23BIT:HARDIRQ Enable Flag

24bit:preempt_active flag bit ( atomic context flag bit??) )

Task: process-related structures that contain richer information

cpu_context:cpu The register value, which should be the thread execution scenario that is preserved when the current process is switched.

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 */

............................

}

Get current thread/process

only need to get the current SP pointer and then 8k byte alignment to find the THREAD_INFO structure

Register Unsignedlong SP ASM ("SP");

Return (Structthread_info *) (SP & ~ (thread_size-1));

Kernel-Provided correlation function structure

Static inline struct thread_info*current_thread_info (void)

and the current macro is used to get the currently process structure body.

Get CPSR Register in C language

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 function call when stack frame

each process has its own stack. Considering the scenario in which a function call occurs when the process executes, the parent function and the child function use the same stack, and in general, it is not necessary to distinguish which part of the stack is used by the parent function and the child function respectively. However, this information is important when you need to backtrace a function call during execution .

simply put, the stack frame is part of a stack used by a function, and the stack frame of all functions forms a complete stack. The two boundaries of a stack frame are defined by the FP and SP, respectively.

All backtrace processes can be identified by the FP pointer

The SP and FP of the parent function can be obtained by stackframe the SP and FP to obtain a stack frame for the parent function (PC,LR,SP, which is usually required for debugging during the execution of the program). The FP will press the stack at the first time of the function call, so that all functions are called in sequence.

The Config_frame_pointer configuration must be turned on for the kernel to support FP pointers

3KernelSave_stack_traceAnalysis

Voidsave_stack_trace (struct stack_trace *trace)

{

Save_stack_trace_tsk (current, trace);

}

Then analyze:

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; // set the call progression that needs to be ignored , generally set to 0

if (tsk! = current) {

#ifdefCONFIG_SMP

/*

* What guarantees does we have this ' tsk ' is not

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

* can ' t guarantee we won ' t explode.

*/

// If you do not save the current CPU the current process on , then it's hard to determine tsk The value of the process register,

Maybe it's changing all the time . .

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

Trace->entries[trace->nr_entries++]= Ulong_max;

Return

#else // in a single CPU ,thetsk process has been switched and can be traced back to 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"); // through SP gets the current stack pointer

//__builtin_frame_address (0) returns the current function's FP Pointers

//__builtin_return_address (0) returns the return address of the current function (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; // the function name gets to the current PC

}

Walk_stackframe (&frame, save_trace,&data); // making a stack walk

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

Trace->entries[trace->nr_entries++]= Ulong_max;

}

which Save_trace Main Save current PC into the array .

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) {// If there is a setting of Skip, The current call is skipped

data->skip--;

return 0;

}

trace->entries[trace->nr_entries++] =ADDR; // Save the current PC

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

}

then analyze Walk_stackframe function

void Notrace walk_stackframe (struct stackframe *frame,

Int (*FN) (struct stackframe *, void *), void *data)

{

while (1) {

int ret;

if (FN (frame, data))// call save_trace Save current pc

Break

ret = Unwind_frame (frame); // put FP pointer moves to the previous function

if (Ret < 0)

Break

}

}


Intnotrace unwind_frame (struct stackframe *frame)

{

unsigned long, low;

unsigned long fp = frame->fp;

/* Only go-a higher address on the stack */

Low = frame->sp; // Current Stack End

High = ALIGN (low, thread_size); // top of current stack

/* Check current frame pointer is within bounds*/

if (FP < low + | | fp > HIGH-4)

Return-einval;

/* Restore the registers from the stack frame*/

from the stack diagram above , The order in which these pointers are placed on the stack is

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 Getting a stack instance

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 Level Call

trace.skip= 0;

Save_stack_trace_tsk (Current,&trace);

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

offset= strlen (msg);

According to the PC,%PF can print out the function name by%PF

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

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

}

}


Linux kernel stack call implementation analysis

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

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.