-1

I want to change the content of the Program Counter (Instruction Pointer). I thought by overriding the system signal handler in C, I can get the pointer in the system stack frame. From there I can get the return address of the function and change it.

However, I got the pointer in the stack, But I don't know exactly where the return address is stored on the Stack Frame.

void signal_handler(int signal){

   char* ptr = (char*) & signal;
   // As, signal is stored on the paramter list of the stack, 
   // I get the address in the current stack frame. From , here
   // I want to change the return address(that is stored in the 
   // current stack frame).
}
Paul R
  • 208,748
  • 37
  • 389
  • 560
P5291
  • 51
  • 1
  • 8
  • 5
    What are you trying to do in broader terms? What are your _needs_? The method you have chosen won't work [well], but there are other ways to achieve [what I suspect] you want, such as `sigsetjmp` and `siglongjmp` – Craig Estey Jan 28 '16 at 23:10
  • Instead of that, you should use `sigaction` where you can mess with the registers in the context. – Jester Jan 28 '16 at 23:10
  • 1
    How can you tell that `int signal` is passed on the stack, and not in a register? – Weather Vane Jan 28 '16 at 23:11
  • 1
    Why do you need a signal handler? Also, why not just use inline assembly and a JMP instruction? (Or BR, or whatever it is on your architecture) – user253751 Jan 28 '16 at 23:12
  • @WeatherVane: This method is called when an interrupt signal is raised. The parameters to a method are stored on the stack. – P5291 Jan 28 '16 at 23:26
  • @CraigEstey : after segmentation fault, the program stops execution. I am trying to execute the next line after the segmentation fault. – P5291 Jan 28 '16 at 23:27
  • @P5291 please quote your sources for where it says that parameters for a method (usually called a *function* in C) must be passed on the stack. If in a register, then `&` of the arg has no meaning. – Weather Vane Jan 28 '16 at 23:30
  • 1
    @P5291: Lines of code don't map 1:1 with asm instructions. Even so, how are you planning to design the program so that has any hope of being useful? – Peter Cordes Jan 28 '16 at 23:31
  • C does not require a stack, stack pointer or program counter. And interrupts are beyond the scope of the C language anyway. A (hardware) interrupt does not generate a C-signal. – too honest for this site Jan 29 '16 at 00:15

2 Answers2

4

After a segfault, the program is in an indeterminate state. You can no longer rely upon anything (e.g. registers) having correct values.

Even if you could return to the next instruction after the fault, unless your signal handler disassembles the offending instruction [in context], and changes register values to compensate, you've now got a program that is untrustworthy and will probably continue to segfault or [worse] operate with far more disastrous results (e.g. unlink on the wrong file, etc).

But, you can't do this because of the signal "trampoline". See the sigreturn man page for details. The stack frame given to your signal handler isn't necessarily even the normal one.

You have to restore the program to a known "safe" state. The only way to do that is [as I mentioned in a comment above] is setting up a recovery point with sigsetjmp and doing siglongjmp inside the signal handler. Side note: Using these is similar to using exceptions in C++, but you have to do much more work manually.

I've done plenty of segfault catching signal handlers with recovery, but they all involve using sigsetjmp/siglongjmp.

This also begs the question: Why not just debug your program so that it doesn't segfault in the first place? What is the special need you have that precludes this?

Craig Estey
  • 30,627
  • 4
  • 24
  • 48
0

If you just want to jump to an address, without setting up the stack for the context you're jumping to, or cleaning it up from the context you're leaving, you could use a GNU C computed-goto.

void *ptr;
/* ... */
ptr = &&foo;

// then somewhere else

goto *ptr;

As I understand it, this is pretty much equivalent to

asm volatile("jmp *ptr");  // AT&T syntax for memory-indirect jump

The correct way to try to recover from a segfault is to use setjmp / longjmp. Trying to do much at that point is highly not recommended. Use this functionality to print a custom message, log something, and exit. If your code caused a segfault, it might well have scribbled over some of your program's data before trying to access some memory it wasn't allowed to. This might even have clobbered the return addresses on the stack.

Even if asm instructions mapped 1:1 to lines of code (which they don't), most programs would break horribly if one line of code was skipped. To say nothing of the fact that you'll only segfault if there's a problem with the data or code that you're trying to resume excution of.

Community
  • 1
  • 1
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847