#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
//#include <asm/ptrace.h>
#include <asm/ptrace_offsets.h>
char *prog_name;
/* this is entry address in kernel gate page for break syscall
* this macro need be changed with kernel
*/
#define __kernel_syscall_via_break 0xa000000000010620UL
/* here is syscall_via_break code in kernel side, break instruction
* is the first slot of the bundle
* GLOBAL_ENTRY(__kernel_syscall_via_break)
* { .mib
* break 0x100000
* nop.i 0
* br.ret.sptk.many b6
*}
*/
static int singlestep_slot1, singlestep_slot2;
void print_instruction (int child_pid, int state)
{
long ip, slot;
unsigned long psr;
ip = ptrace (PTRACE_PEEKUSER, child_pid, PT_CR_IIP, 0);
psr = ptrace(PTRACE_PEEKUSER, child_pid, PT_CR_IPSR, 0);
slot = (psr >> 41) & 0x3;
if (ip == __kernel_syscall_via_break) {
if (slot == 1)
singlestep_slot1++;
else if (slot == 2)
singlestep_slot2++;
}
}
int main (int argc, char **argv, char **envp)
{
int status, pid, child_pid, state = 1, arg = 1;
int ret;
singlestep_slot1 = singlestep_slot2 = 0;
prog_name = argv[0];
child_pid = fork ();
if (child_pid == 0)
{
ptrace (PTRACE_TRACEME, 0, 0, 0);
execve (argv[arg], argv + arg, envp);
printf ("%s: execve failed (errno=%d)\n", prog_name, errno);
exit(-2);
}
while (1)
{
pid = wait4 (-1, &status, 0, 0);
if (pid == -1)
{
if (errno == EINTR)
continue;
printf ("%s: wait4() failed (errno=%d)\n", prog_name, errno);
}
if (WIFSIGNALED (status) || WIFEXITED (status)
|| (WIFSTOPPED (status) && WSTOPSIG (status) != SIGTRAP))
{
if (WIFEXITED (status))
{
printf ("%s: exit status %d\n", prog_name, WEXITSTATUS (status));
break;
}
else if (WIFSIGNALED (status))
{
printf ("%s: terminated by signal %d\n",
prog_name, WTERMSIG (status));
}
else {
printf ("%s: got signal %d\n", prog_name, WSTOPSIG (status));
}
}
print_instruction (child_pid, state);
ptrace (PTRACE_SINGLESTEP, child_pid, 0, 0);
}
if (WEXITSTATUS (status) == 0) {
if (singlestep_slot1 == 0)
printf("single step on syscall failed\n");
else {
printf("single step on syscall succeed\n");
printf("single step on break bundle slot 0: %d slot 1: %d \n",
singlestep_slot1, singlestep_slot2);
}
}
return 0;
}