我有以下两个文件,第一个为SIGUSR1创建一个信号处理程序,它在中断的上下文中设置对函数foo()的伪调用。第二个文件是用于访问IA32寄存器的模板头。
stack.c:
#ifdef HARMONY
#define LINUX
#include "hythread.h"
#endif
#ifndef _GNU_SOURCE
#define _GNU_SOURCE // so that string.h will include strsignal()
#endif
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/mman.h>
#include <errno.h>
#include <string.h>
#include <stdarg.h> // va_list, va_start(), va_end()
#ifndef __USE_GNU // Deal with current ucontext ugliness. The current
#define __USE_GNU // mess of asm/ucontext.h & sys/ucontext.h and their
#include <sys/ucontext.h> // mutual exclusion on more recent versions of gcc
#undef __USE_GNU // dictates this ugly hack.
#else
#include <sys/ucontext.h>
#endif
#include <assert.h>
#include "linux_ucontext.h"
#define DBG(fncn,name) if (fncn) { perror(name); return 1; }
void foo(void *fp) {
printf("Inside foo(%p)\n", fp);
}
typedef long unsigned int* Address;
void handler(int signo, siginfo_t *si, void *context) {
if (signo == SIGUSR1) {
printf("Handling SIGUSR1...\n");
// Set fake pointer (0xDEADBEEF) as first argument to foo()
Address sp = (Address)IA32_ESP(context);
IA32_ESP(context) = IA32_ESP(context) - sizeof(void *);
sp = (Address)IA32_ESP(context);
((Address *)sp)[0] = IA32_EIP(context);
IA32_EAX(context) = 0xDEADBEEF;
// Put return address of interrupted instruction onto stack
IA32_ESP(context) = IA32_ESP(context) - sizeof(void *);
sp = IA32_ESP(context);
((Address *)sp)[0] = IA32_EIP(context);
// Setup function call to foo()
IA32_EIP(context) = foo;
return;
}
printf("Received unknown signal signo=%d\n",signo);
}
int main(int argc, char *argv[]) {
struct sigaction action;
memset(&action, 0, sizeof(action));
action.sa_sigaction = &handler;
// Mask all signals from reaching handler while handler is running
DBG(sigfillset(&(action.sa_mask)),"sigfillset");
DBG(sigdelset(&(action.sa_mask), SIGCONT),"sigdelset");
action.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_RESTART;
action.sa_sigaction = &handler;
DBG(sigaction(SIGUSR1, &action, 0),"sigaction")
int count = 0;
while (1) {
sleep(1);
printf("Inside while loop %08d...\n",count);
count += 1;
}
}
linux_context.h:
/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Eclipse Public License (EPL);
* You may not use this file except in compliance with the License. You
* may obtain a copy of the License at
*
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
#ifndef JRVM_LINUX_IA32_UCONTEXT
#define JRVM_LINUX_IA32_UCONTEXT
#define __MC(context) ((ucontext_t*)context)->uc_mcontext
#define __GREGS(context) (__MC(context).gregs)
#ifndef __x86_64__
# define IA32_EAX(context) (__GREGS(context)[REG_EAX])
# define IA32_EBX(context) (__GREGS(context)[REG_EBX])
# define IA32_ECX(context) (__GREGS(context)[REG_ECX])
# define IA32_EDX(context) (__GREGS(context)[REG_EDX])
# define IA32_EDI(context) (__GREGS(context)[REG_EDI])
# define IA32_ESI(context) (__GREGS(context)[REG_ESI])
# define IA32_EBP(context) (__GREGS(context)[REG_EBP])
# define IA32_ESP(context) (__GREGS(context)[REG_ESP])
# define IA32_EIP(context) (__GREGS(context)[REG_EIP])
# define IA32_CS(context) (__GREGS(context)[REG_CS])
# define IA32_DS(context) (__GREGS(context)[REG_DS])
# define IA32_ES(context) (__GREGS(context)[REG_ES])
# define IA32_FS(context) (__GREGS(context)[REG_FS])
# define IA32_GS(context) (__GREGS(context)[REG_GS])
# define IA32_SS(context) (__GREGS(context)[REG_SS])
# define IA32_OLDMASK(context) (__MC(context).oldmask)
# define IA32_FPFAULTDATA(context) (__MC(context).cr2)
#else
# define IA32_EAX(context) (__GREGS(context)[REG_RAX])
# define IA32_EBX(context) (__GREGS(context)[REG_RBX])
# define IA32_ECX(context) (__GREGS(context)[REG_RCX])
# define IA32_EDX(context) (__GREGS(context)[REG_RDX])
# define IA32_EDI(context) (__GREGS(context)[REG_RDI])
# define IA32_ESI(context) (__GREGS(context)[REG_RSI])
# define IA32_EBP(context) (__GREGS(context)[REG_RBP])
# define IA32_ESP(context) (__GREGS(context)[REG_RSP])
# define IA32_EIP(context) (__GREGS(context)[REG_RIP])
#endif
#define IA32_EFLAGS(context) (__GREGS(context)[REG_EFL])
#define IA32_TRAPNO(context) (__GREGS(context)[REG_TRAPNO])
#define IA32_ERR(context) (__GREGS(context)[REG_ERR])
#define IA32_FALUTVADDR(context) (__GREGS(context)[REG_CS])
#define IA32_FPREGS(context) (__MC(context).fpregs)
// reg = 0..7, n = 0 .. 3
#define IA32_STMM(context, reg, n) (IA32_FPREGS(context)->_st[reg].significand[n])
#define IA32_STMMEXP(context, reg) (IA32_FPREGS(context)->_st[reg].exponent)
/* Currently unused
#define IA32_XMM(context, reg, n) \
*/
#endif
当我编译并运行它,并使用SIGUSR1命中进程时,foo()被正确调用并返回到while循环。但是,当我设置一个类似的信号处理程序来中断某些任意代码(运行JVM)时,假的&#34; foo()&#34;正确执行,但当它返回到任意中断代码时,进程分段出错。
我是否在假函数调用中破坏了一些寄存器?在尝试将0xDEADBEEF传递给foo时我做错了什么(现在它似乎正在打印垃圾指针)?