frame.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 344 行

C
344
字号
/*  * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <signal.h>#include <wait.h>#include <sched.h>#include <errno.h>#include <sys/ptrace.h>#include <sys/syscall.h>#include <sys/mman.h>#include <asm/page.h>#include <asm/ptrace.h>#include <asm/sigcontext.h>#include "sysdep/ptrace.h"#include "sysdep/sigcontext.h"#include "frame_user.h"#include "kern_util.h"#include "user_util.h"#include "ptrace_user.h"#include "os.h"static int capture_stack(int (*child)(void *arg), void *arg, void *sp,			 unsigned long top, void **data_out){	unsigned long regs[FRAME_SIZE];	int pid, status, n, len;	/* Start the child as a thread */	pid = clone(child, sp, CLONE_VM | SIGCHLD, arg);	if(pid < 0){		printf("capture_stack : clone failed - errno = %d\n", errno);		exit(1);	}	/* Wait for it to stop itself and continue it with a SIGUSR1 to force 	 * it into the signal handler.	 */	CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));	if(n < 0){		printf("capture_stack : waitpid failed - errno = %d\n", errno);		exit(1);	}	if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)){		fprintf(stderr, "capture_stack : Expected SIGSTOP, "			"got status = 0x%x\n", status);		exit(1);	}	if(ptrace(PTRACE_CONT, pid, 0, SIGUSR1) < 0){		printf("capture_stack : PTRACE_CONT failed - errno = %d\n", 		       errno);		exit(1);	}	/* Wait for it to stop itself again and grab its registers again.  	 * At this point, the handler has stuffed the addresses of	 * sig, sc, and SA_RESTORER in raw.	 */	CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));	if(n < 0){		printf("capture_stack : waitpid failed - errno = %d\n", errno);		exit(1);	}	if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)){		fprintf(stderr, "capture_stack : Expected SIGSTOP, "			"got status = 0x%x\n", status);		exit(1);	}	if(ptrace(PTRACE_GETREGS, pid, 0, regs) < 0){		printf("capture_stack : PTRACE_GETREGS failed - errno = %d\n", 		       errno);		exit(1);	}	/* It has outlived its usefulness, so continue it so it can exit */	if(ptrace(PTRACE_CONT, pid, 0, 0) < 0){		printf("capture_stack : PTRACE_CONT failed - errno = %d\n", 		       errno);		exit(1);	}	CATCH_EINTR(n = waitpid(pid, &status, 0));	if(n < 0){		printf("capture_stack : waitpid failed - errno = %d\n", errno);		exit(1);	}	if(!WIFSIGNALED(status) || (WTERMSIG(status) != 9)){		printf("capture_stack : Expected exit signal 9, "		       "got status = 0x%x\n", status);		exit(1);	}	/* The frame that we want is the top of the signal stack */	len = top - PT_SP(regs);	*data_out = malloc(len);	if(*data_out == NULL){		printf("capture_stack : malloc failed - errno = %d\n", errno);		exit(1);	}	memcpy(*data_out, (void *) PT_SP(regs), len);	return(len);}struct common_raw {	void *stack;	int size;	unsigned long sig;	unsigned long sr;	unsigned long sp;		struct arch_frame_data_raw arch;};#define SA_RESTORER (0x04000000)typedef unsigned long old_sigset_t;struct old_sigaction {	__sighandler_t handler;	old_sigset_t sa_mask;	unsigned long sa_flags;	void (*sa_restorer)(void);};static void child_common(struct common_raw *common, sighandler_t handler,			 int restorer, int flags){	stack_t ss = ((stack_t) { .ss_sp	= common->stack,				  .ss_flags	= 0,				  .ss_size	= common->size });	int err;	if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){		printf("PTRACE_TRACEME failed, errno = %d\n", errno);	}	if(sigaltstack(&ss, NULL) < 0){		printf("sigaltstack failed - errno = %d\n", errno);		kill(getpid(), SIGKILL);	}	if(restorer){		struct sigaction sa;		sa.sa_handler = handler;		sigemptyset(&sa.sa_mask);		sa.sa_flags = SA_ONSTACK | flags;		err = sigaction(SIGUSR1, &sa, NULL);	}	else {		struct old_sigaction sa;		sa.handler = handler;		sa.sa_mask = 0;		sa.sa_flags = (SA_ONSTACK | flags) & ~SA_RESTORER;		err = syscall(__NR_sigaction, SIGUSR1, &sa, NULL);	}		if(err < 0){		printf("sigaction failed - errno = %d\n", errno);		kill(getpid(), SIGKILL);	}	os_stop_process(os_getpid());}/* Changed only during early boot */struct sc_frame signal_frame_sc;struct sc_frame signal_frame_sc_sr;struct sc_frame_raw {	struct common_raw common;	unsigned long sc;	int restorer;};/* Changed only during early boot */static struct sc_frame_raw *raw_sc = NULL;static void sc_handler(int sig, struct sigcontext sc){	raw_sc->common.sig = (unsigned long) &sig;	raw_sc->common.sr = frame_restorer();	raw_sc->common.sp = frame_sp();	raw_sc->sc = (unsigned long) &sc;	setup_arch_frame_raw(&raw_sc->common.arch, &sc + 1, raw_sc->common.sr);	os_stop_process(os_getpid());	kill(getpid(), SIGKILL);}static int sc_child(void *arg){	raw_sc = arg;	child_common(&raw_sc->common, (sighandler_t) sc_handler, 		     raw_sc->restorer, 0);	return(-1);}/* Changed only during early boot */struct si_frame signal_frame_si;struct si_frame_raw {	struct common_raw common;	unsigned long sip;	unsigned long si;	unsigned long ucp;	unsigned long uc;};/* Changed only during early boot */static struct si_frame_raw *raw_si = NULL;static void si_handler(int sig, siginfo_t *si, struct ucontext *ucontext){	raw_si->common.sig = (unsigned long) &sig;	raw_si->common.sr = frame_restorer();	raw_si->common.sp = frame_sp();	raw_si->sip = (unsigned long) &si;	raw_si->si = (unsigned long) si;	raw_si->ucp = (unsigned long) &ucontext;	raw_si->uc = (unsigned long) ucontext;	setup_arch_frame_raw(&raw_si->common.arch, 			     ucontext->uc_mcontext.fpregs, raw_si->common.sr);		os_stop_process(os_getpid());	kill(getpid(), SIGKILL);}static int si_child(void *arg){	raw_si = arg;	child_common(&raw_si->common, (sighandler_t) si_handler, 1,  		     SA_SIGINFO);	return(-1);}static int relative_sr(unsigned long sr, int sr_index, void *stack, 		       void *framep){	unsigned long *srp = (unsigned long *) sr;	unsigned long frame = (unsigned long) framep;	if((*srp & PAGE_MASK) == (unsigned long) stack){		*srp -= sr;		*((unsigned long *) (frame + sr_index)) = *srp;		return(1);	}	else return(0);}static unsigned long capture_stack_common(int (*proc)(void *), void *arg, 					  struct common_raw *common_in, 					  void *top, void *sigstack, 					  int stack_len, 					  struct frame_common *common_out){	unsigned long sig_top = (unsigned long) sigstack + stack_len, base;	common_in->stack = (void *) sigstack;	common_in->size = stack_len;	common_out->len = capture_stack(proc, arg, top, sig_top, 					&common_out->data);	base = sig_top - common_out->len;	common_out->sig_index = common_in->sig - base;	common_out->sp_index = common_in->sp - base;	common_out->sr_index = common_in->sr - base;	common_out->sr_relative = relative_sr(common_in->sr, 					      common_out->sr_index, sigstack, 					      common_out->data);	return(base);}void capture_signal_stack(void){	struct sc_frame_raw raw_sc;	struct si_frame_raw raw_si;	void *stack, *sigstack;	unsigned long top, base;	stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,		     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);	sigstack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,			MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);	if((stack == MAP_FAILED) || (sigstack == MAP_FAILED)){		printf("capture_signal_stack : mmap failed - errno = %d\n", 		       errno);		exit(1);	}	top = (unsigned long) stack + PAGE_SIZE - sizeof(void *);	/* Get the sigcontext, no sigrestorer layout */	raw_sc.restorer = 0;	base = capture_stack_common(sc_child, &raw_sc, &raw_sc.common, 				    (void *) top, sigstack, PAGE_SIZE, 				    &signal_frame_sc.common);	signal_frame_sc.sc_index = raw_sc.sc - base;	setup_arch_frame(&raw_sc.common.arch, &signal_frame_sc.common.arch);	/* Ditto for the sigcontext, sigrestorer layout */	raw_sc.restorer = 1;	base = capture_stack_common(sc_child, &raw_sc, &raw_sc.common, 				    (void *) top, sigstack, PAGE_SIZE, 				    &signal_frame_sc_sr.common);	signal_frame_sc_sr.sc_index = raw_sc.sc - base;	setup_arch_frame(&raw_sc.common.arch, &signal_frame_sc_sr.common.arch);	/* And the siginfo layout */	base = capture_stack_common(si_child, &raw_si, &raw_si.common, 				    (void *) top, sigstack, PAGE_SIZE, 				    &signal_frame_si.common);	signal_frame_si.sip_index = raw_si.sip - base;	signal_frame_si.si_index = raw_si.si - base;	signal_frame_si.ucp_index = raw_si.ucp - base;	signal_frame_si.uc_index = raw_si.uc - base;	setup_arch_frame(&raw_si.common.arch, &signal_frame_si.common.arch);	if((munmap(stack, PAGE_SIZE) < 0) || 	   (munmap(sigstack, PAGE_SIZE) < 0)){		printf("capture_signal_stack : munmap failed - errno = %d\n", 		       errno);		exit(1);	}}/* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically * adjust the settings for this buffer only.  This must remain at the end * of the file. * --------------------------------------------------------------------------- * Local variables: * c-file-style: "linux" * End: */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?