I am trying to develop a runtime stack tracer. I have a function that returns the EIP address whenever the program being traced segfaults. How can I get back to the ebp of the current function (the one during which the program under observation crashed) so that I can start tracing up?
There is no way to convert an instruction pointer to a stack frame pointer. The same function may be invoked many times (even recursively) with different stack addresses; that's the whole point of having a call stack. If you have a crash dump file (core file, etc.) it should contain a dump of all the registers. If you want the register values you must read them from here.
The current ebp and esp (and all other registers) at the time of the segfault is available in the ucontext, which is passed as the third argument to the signal handler. The details of what's where in the ucontext is OS and CPU specific.
Related
When I use gdb to debug process in arm linux I can use call like call write(123,"abc",3)
How does gdb inject that call into process and recover all?
How does gdb inject that call into process and recover all?
GDB can read and write the inferior (being debugged) process memory using ptrace system call.
So it reads and saves in its own memory some chunk of instructions from inferior (say 100 bytes).
Then it overwrites this chunk with new instructions, which look something like:
r0 = 123
r1 = pointer to "abc"
r2 = 3
BLR write
BKPT
Now GDB saves the current inferior registers, sets ip to point to the chunk of instructions it just wrote, and resumes the inferior.
Inferior executes instructions until it reaches the breakpoint, at which point GDB regains control. It can now look at the return register to know what write returned and print it. GDB now restores the original instructions and original register values, and we are back as if nothing happened.
P.S. This is a general description of how "call function in inferior" works; I do not claim that this is exactly how it works.
There are also complications: if write calls back into the code that GDB overwrote, it wouldn't work. So in reality GDB uses some other mechanism to obtain suitable "scratch area" in the inferior. Also, the "abc" string requires scratch area as well.
I trying to understand the internals of the Linux kernel by reading Robert Love's Linux Kernel Development.
On page 74 he says the easiest way to pass arguments to a syscall is via :
Somehow, user-space must relay the parameters to the kernel during the
trap.The easiest way to do this is via the same means that the syscall
number is passed: The parameters are stored in registers. On x86-32,
the registers ebx, ecx, edx, esi, and edi contain, in order, the first
five arguments.
Now this is bothering me for a number of reasons:
All syscalls are defined with the asmlinkage option. Which implies that the arguments are always to be found on the stack and not the register. So what is all this business with the registers ?
It may be possible that before the syscall is performed the values are copied on to the kernel stack. I have no idea why that would be efficient but it might be a possibility.
(This answer is for 32-bit x86 Linux to match your question; things are slightly different for 64-bit x86 and other architectures.)
The parameters are passed from userspace in registers as Love says.
When userspace invokes a system call with int $0x80, the kernel syscall entry code gets control. This is written in assembly language and can be seen here, for instance. One of the things this code does is to take the parameters from the registers and push them onto the stack, and then call the appropriate kernel sys_XXX() function (which is written in C). So those functions do indeed expect their arguments on the stack.
It wouldn't work as well to try to pass parameters from userspace to the kernel on the stack. When the system call is made, the CPU switches to a separate kernel stack, so the parameters would have to be copied from the userspace stack to the kernel stack, and this is somewhat complicated. And it would have to be done even for very simple system calls that just take a few numeric arguments and wouldn't otherwise need to access userspace memory at all (think about close() for instance).
Honestly, I am really confused with this particular virtual memory related concept.
Q1) When a page fault occurs, does the processor first finishes the execution of the current instruction and then moves the IP register contents (address of next instruction) to the stack? Or, it aborts current instruction being executed and moves the contents of instruction pointer register to stack?
Q2) If the second case is true, then how does it resume the instruction which was aborted because when if it resumes, the stack contains the instruction pointer value which is nothing but the address of the next instruction. So it will never resume the instruction where the page fault occurred.
What I think
I think the second case sounds wrong. The confusion occurred while i was reading Operating System Principles by Silbershatz and Galvin. In that they have written
when a page fault occurs, we will have to bring in the desired page, correct page table and restart the instruction.
But the instruction pointer always points to the address of the next instruction so it means, according to what this book is trying to convey, we are decrementing the value of IP just to restart the execution of the instruction where the page fault occurred?
In the Intel System Programming guide, chapter 6.5, it says
Faults — A fault is an exception that can generally be corrected and that, once corrected, allows the program
to be restarted with no loss of continuity. When a fault is reported, the processor restores the machine state to
the state prior to the beginning of execution of the faulting instruction. The return address (saved contents of
the CS and EIP registers) for the fault handler points to the faulting instruction, rather than to the instruction
following the faulting instruction.
A page fault is classified as a fault (no surprises there), so when a page fault happened you're in the state "before it ever happened" - well not really, because you're in the fault handler (so EIP and ESP are definitely different, also CR2 contains the address), but when you return it'll be the state before the ever happened, only with changes made by the handler (so, put there page there, or kill the process)
I have seen this: Implementing a User-Level Threads Package and it doesn't apply.
During the implementation of Thread_new(int func(void*)), that assigns a thread and creates a stack, I am unable to think of a way to set the program counter (%eip) if I am correct, so when the thread is started by the scheduler, it starts at the given function's (func) entry point.
Although I have seen many c-only (no assembly) implementations, we have been given the following code (x86):
_thrstart:
pushl %edi
call *%esi
pushl %eax
call Thread_exit
Is there a specific reason to push %edi to the stack? I can't seem to find another use for esi/edi apart from byte copying.
I realize that the indirect call to *%esi is probably used to call the function from the context of the new thread, but apart from that, I don't seem to understand how (or what) %esi points to being a valid function address when _thrstart is called from Thread_new
NOTES:
Thread_exit is the cleanup thread, implemented in c.
This is HOMEWORK
In general; you can break "scheduler" down into 4 parts.
The first part is the mechanics of switching from one thread to another. This mostly involves storing the previous thread's state somewhere and loading the next thread's state from somewhere. Here, "somewhere" could be some sort of thread control block, or it could be the thread's stack, or both, or something else. A thread's state may include the contents of general purpose registers, it's stack top (esp), it's instruction pointer (eip), and anything else (MMX/SSE/AVX registers). However, for co-operative scheduling a thread's state could be much less (e.g. most of a thread's state is trashed by thread switching and cooperative scheduling is used so that the thread itself knows when its state is going to be trashed and can prepare for that).
The second part is deciding when to do a thread switch and which thread to switch to. This varies widely for different schedulers.
The third part is starting a thread. This mostly involves constructing the data that would be loaded during a thread switch. However, it's possible to do this in a "lazy" way, where you only create the minimal amount of state when first creating a thread, and then finish creating the remainder of the thread's state after it has been given CPU time.
The fourth part is terminating a thread. This involves destroying/freeing the data that would be loaded during a thread switch; but can also mean cleaning up any resources that the thread failed to release (e.g. file handles, network connections, thread local storage, whatever) so that you don't end up with "resource leaks".
Typically, in simple RTOessess, threads are not started by being called or jumped to - they are started by being returned or interrupt-returned to.
The trick is to assemble data at the top of the new stack so that is looks as if the thread has been running before and has either called the scheduler or entered it via an interrupt. At the bottom of this 'frame' should be the address of the thread function. You can then load the stack pointer with the address of the frame, enable interrupts and and perform a RET or IRET to start the thread function.
It's convenient to also first shove on a parameter that the new thread can retrieve and a call to the 'TerminateThread' or 'Thread_Exit', so that if the thread function returns, the scheduler can terminate it.
Seems that the problem wasn't as complicated as before.
Based on the answer given by #Martin James, the Stack is prepared so that the return address is the _thrstart function.
Based on the assembly used to perform a context switch, the registers edi and esi are stored in specific locations on the stack (when the thread is inactive). By using edi and esi as general purpose registers, edi contains the void* argument, and esi contains the address of the function to be called from the new thread.
_thrstart:
pushl %edi #pushes argument for function func to the stack
call *%esi #indirect call to func
pushl %eax #Expect return value in eax, push to stack
call Thread_exit #Call thread cleanup
As developing on ARM based project, we get data abort randomly, that is when we play with it we get a data abort interrupt. But the data abort is not always on the same point when we check with the register map with r14 or r13, even though check the function callback. Is there anyway that I can get the information about the root cause on data abort precisely? I have try the ref2 but could not get the same point when I trap the data about interrupt.
Related
ARM Data Abort error exception debugging
ARM: HOW TO ANALYZE A DATA ABORT EXCEPTION
Checking the link register (r14) as described in your Keil link above will show you the instruction that triggered the data abort. From there you'll have to figure out why it triggered a data abort and how that could have happened, which is the difficult part.
In my experience what most likely happened is that you accessed an invalid pointer. It can be invalid for many reasons. Here are a few candidates:
You used the pointer before it was initialized
You used the pointer after it, or the containing memory, had been freed (and was subsequently modified when another function allocated it)
The pointer was corrupted by a stack overflow
The pointer was corrupted by other, unrelated, misbehaving code that is trampling on memory
The pointer was allocated on the stack as a local variable and then used after the allocating function had exited
The pointer has incorrect alignment for its type (for example, trying to access 0x4001 as a uint32_t)
As you can see, lots of things can be the root cause of an ARM data abort. Finding the root cause is part of what makes ARM software/firmware development so much fun! Good luck figuring out your puzzle.