5

Is there any way to figure out address of machine instruction, that was interrupted by some signal? Assuming that we are at handler established by sigaction() and have all access to passed siginfo_t and ucontext_t. As far as I see man pages says nothing about it.

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
Sergio
  • 8,099
  • 2
  • 26
  • 52

2 Answers2

5

Lets see below example for linux and x86 architure

#include<stdio.h>
#define __USE_GNU
#include<signal.h>
#include<ucontext.h>

void myhandle(int mysignal, siginfo_t *si, void* arg)
{    
  ucontext_t *context = (ucontext_t *)arg;
  printf("Address from where crash happen is %x \n",context->uc_mcontext.gregs[REG_RIP]);
  context->uc_mcontext.gregs[REG_RIP] = context->uc_mcontext.gregs[REG_RIP] + 0x04 ;

}

int main(int argc, char *argv[])
{
  struct sigaction action;
  action.sa_sigaction = &myhandle;
  action.sa_flags = SA_SIGINFO;
  sigaction(11,&action,NULL);

  printf("Before segfault\n");

  int *a=NULL;
  int b;
  b =*a; // Here crash will hapen

  printf("I am still alive\n");

  return 0;
}

Now compile and run and see discompiled instrustion sets.

jeegar@jeegar:~/stackoverflow$ gcc -g test1.c  -o test1.o
jeegar@jeegar:~/stackoverflow$ ./test1.o 
Before segfault
Signal is 11
Address from where crash happen is 40065b 
I am still alive
jeegar@jeegar:~/stackoverflow$ objdump -S test1.o 

Here in object dump

  printf("Before segfault\n");
  400645:   bf a8 07 40 00          mov    $0x4007a8,%edi
  40064a:   e8 21 fe ff ff          callq  400470 <puts@plt>

  int *a=NULL;
  40064f:   48 c7 45 f0 00 00 00    movq   $0x0,-0x10(%rbp)
  400656:   00 
  int b;
  b =*a; // Here crash will hapen
  400657:   48 8b 45 f0             mov    -0x10(%rbp),%rax
  40065b:   8b 00                   mov    (%rax),%eax
  40065d:   89 45 fc                mov    %eax,-0x4(%rbp)

  printf("I am still alive\n");
  400660:   bf b8 07 40 00          mov    $0x4007b8,%edi
  400665:   e8 06 fe ff ff          callq  400470 <puts@plt>

At 40065b address which machine code is there and which line of your code has done this.


Here i have given you and example code, where segmentation happen and on system's Seg fault signal one handler will be called and in that i have fetched the address of last executated machine cycle and print that address. To varify that address i have also shown the object dump of that code and segmentation falt line's machine instruction matches.

I think this is what you want.

Jeegar Patel
  • 26,264
  • 51
  • 149
  • 222
  • 2
    Signal unsafe functions in the signal handler. And in C you do not need a cast to convert a `void*` to any other data pointer. – Maxim Egorushkin Jan 25 '16 at 10:36
  • @MaximEgorushkin without cast how can i use that pointer?> – Jeegar Patel Jan 25 '16 at 10:38
  • 3
    While Maxim is correct (do not use printf in sighandler), I think it's irrelevant for the purpose of this post (to explain what the OP asked). And casting (void*) is a matter of style. Voting up. – Ctx Jan 25 '16 at 10:40
  • Dropping implementation roughnesses, this answer tells about the same approach as http://stackoverflow.com/a/34990181/2878070. See my comment below. – Sergio Jan 25 '16 at 10:41
  • @Ctx I disagree, unnecessary code make your applications worse. It is easy to make things bigger, it is hard to make them any better. And imagine you come to a doctor and he tells you things that you know are plain wrong. You would probably find another doctor. – Maxim Egorushkin Jan 25 '16 at 10:41
  • @MaximEgorushkin Following that paradigma, every C-program would consist of one function with one line of code in it when technically possible. Nonsense! And I do not get what you try to convey with your doctor-example – Ctx Jan 25 '16 at 10:42
  • Printf were used just for informative purpose and printing that address. So yes those are not required but for that downvote ;) Really? – Jeegar Patel Jan 25 '16 at 10:43
  • Are you quite sure you need to clear the direction flag after returning from the handler? – EOF Jan 25 '16 at 11:43
  • @EOF i did not get you...what you mean... – Jeegar Patel Jan 25 '16 at 11:50
  • @JeegarPatel: Your `printf()` *in a signal handler* shows the faulting instruction at `0x40065b`. You adjust the instruction pointer by `0x4`, so to `0x40065f`. That is the last byte of `40065d: 89 45 fc mov %eax,-0x4(%rbp)`, a `0xfc`, aka `CLD`. – EOF Jan 25 '16 at 12:28
  • @EOF yea that is also not needed. But as a generic i will not be sure from where this crash happen so to avoid further jumping wrong address and dont i miss any instruction, i have kept 4 as just for example... – Jeegar Patel Jan 25 '16 at 12:31
4

Not portable. But this is for x86_64:

The structure ucontext_t contains the value of the register REG_RIP, which should hold the value you look for. This is the first instruction, which will be executed, after returning from the sighandler.

Other architectures should have similar registers (EIP on x86_32, etc.).

Ctx
  • 18,090
  • 24
  • 36
  • 51
  • Yes, but unfortunately there is no guarantee, that first instruction after handler will be that interrupted instruction, due handler may be invoked via few wrappers, and as result this pseudo-IP may point to something inside libc or whatever, but not to our code. Anyway - thanks for your answer. – Sergio Jan 25 '16 at 10:29
  • @Serhio a single machine instruction is never interrupted, not even by a hardware interrupt. It is always completed first. But that's not what you meant. You mean, if the IP is somewhere inside a library, you want the address of the call-instruction in your main code? – Ctx Jan 25 '16 at 10:39
  • yes, saying more precisely, I need to obtain address of application-side instruction (not libc's one), that will be executed after signal handler. E.g. address that is immediately after instruction that caused SIGSEGV. – Sergio Jan 25 '16 at 10:46
  • @Serhio But this would just be exactly the address in REG_RIP. I think you have some confusion here. – Ctx Jan 25 '16 at 10:59
  • As we see in Jeegar's answer - on x64, frame of signal handler is opened right after frame where signal was triggered, so when handler returns we will back to our own frame. But there is no guarantee that there will be no intermediate stack frames between our signal issuer frame and signal handler frame. At least on ARM Android I see three intermediate frames between them, and as result IP from ucontext_t leads me to the last of this internal frames, not to signal issuer. Alternatively we can walk through `uc_link` list to see another contexts. But we have no sign to know where to stop. – Sergio Jan 25 '16 at 11:21
  • 1
    @Serhio No, when the handler returns, the registers are reset to the states like they were at the time of the signal, saved in the ucontext_t-structure by the kernel (RIP, RSP, RBP, etc. pp.). And somehow you seem to mix up the instruction- and stackpointers. – Ctx Jan 25 '16 at 11:32
  • Seems like I've found explanation of these extra frames. In my case android runtime establishes own signal handling chain and exposes own version of `sigaction()` that in some cases doesn't pass arguments to kernel via libc function but rather adds new handlers to own chain. And probably dynamic linker prefers this overrode function for my DSO instead of traditional `sigaction()` from libc somehow. And my handler appears to be invoked from some of the chain members. So, question is closed. Thanks to you all, folks! – Sergio Jan 25 '16 at 13:53