Stackdb
Stackdb is a stackable, multi-target and -level source debugger and memory forensics library.
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
qemuhacks.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014 The University of Utah
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of
7  * the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18 
19 #include <errno.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <sys/mman.h>
25 #include <signal.h>
26 #include <dlfcn.h>
27 
28 static void *(*real_mmap)(void *addr,size_t length,int prot,int flags,
29  int fd,off_t offset) = NULL;
30 static int (*real_unlink)(const char *name) = NULL;
31 static int (*real_atexit)(void (*function)(void)) = NULL;
32 static int (*real_sigaction)(int signum,const struct sigaction *act,
33  struct sigaction *oldact) = NULL;
34 
35 static char **files = NULL;
36 static unsigned int files_size = 0;
37 
38 static void (*qemu_sigint_handler)(int signo,siginfo_t *siginfo,void *c) = NULL;
39 static void (*qemu_sigterm_handler)(int signo,siginfo_t *siginfo,void *c) = NULL;
40 static void (*qemu_sighup_handler)(int signo,siginfo_t *siginfo,void *c) = NULL;
41 
42 static int use_atexit = 0;
43 static int use_sig_override = 1;
44 static int no_cleanup = 0;
45 
46 static void cleanup(void) {
47  unsigned int i;
48 
49  for (i = 0; i < files_size; ++i) {
50  real_unlink(files[i]);
51  free(files[i]);
52  }
53 
54  free(files);
55 }
56 
57 /*
58  * QEMU on POSIX OSes catches SIGINT, SIGHUP, SIGTERM, and dies. This
59  * is both the internal and external kill mechanism (i.e., if the
60  * machine shuts itself down). We know the machine is going to die at
61  * this point, so cleanup, then call its sighandler!
62  */
63 static void sig_override_handler(int signal,siginfo_t *info,void *x) {
64  cleanup();
65  if (signal == SIGINT)
66  qemu_sigint_handler(signal,info,x);
67  if (signal == SIGTERM)
68  qemu_sigterm_handler(signal,info,x);
69  if (signal == SIGHUP)
70  qemu_sighup_handler(signal,info,x);;
71 }
72 
73 /*
74  * But unfortunately, QEMU unlink()s before it sets sighandlers. So we
75  * have to catch sigaction too.
76  */
77 int sigaction(int signum,const struct sigaction *act,struct sigaction *oldact) {
78  char *ev;
79  struct sigaction ouract;
80 
81  if (!real_sigaction)
82  real_sigaction = dlsym(RTLD_NEXT,"sigaction");
83 
84  ev = getenv("QEMU_NO_CLEANUP");
85  if (ev) {
86  no_cleanup = 1;
87  use_atexit = 0;
88  use_sig_override = 0;
89  }
90  ev = getenv("QEMU_USE_ATEXIT");
91  if (ev) {
92  use_atexit = 1;
93  use_sig_override = 0;
94  }
95  ev = getenv("QEMU_USE_SIGOVERRIDE");
96  if (ev) {
97  use_atexit = 0;
98  use_sig_override = 1;
99  }
100 
101  if (no_cleanup)
102  goto real;
103 
104  /*
105  * Ok, intercept a few signals we know QEMU dies on.
106  */
107  if (signum == SIGINT || signum == SIGTERM || signum == SIGHUP) {
108  memset(&ouract,0,sizeof(ouract));
109  ouract.sa_sigaction = sig_override_handler;
110  ouract.sa_mask = act->sa_mask;
111  ouract.sa_flags = act->sa_flags;
112 
113  if (signum == SIGINT)
114  qemu_sigint_handler = act->sa_sigaction;
115  else if (signum == SIGTERM)
116  qemu_sigterm_handler = act->sa_sigaction;
117  else if (signum == SIGHUP)
118  qemu_sighup_handler = act->sa_sigaction;
119 
120  return real_sigaction(signum,&ouract,oldact);
121  }
122  else
123  goto real;
124 
125  real:
126  return real_sigaction(signum,act,oldact);
127 }
128 
129 /*
130  * Wrap unlink to not unlink if @pathname starts with $QEMU_MEMPATH_PREFIX !
131  */
132 int unlink(const char *pathname) {
133  char *prefix;
134 
135  prefix = getenv("QEMU_MEMPATH_PREFIX");
136  if (prefix && strncmp(prefix,pathname,strlen(prefix)) == 0) {
137  errno = 0;
138  files = realloc(files,files_size + 1);
139  files[files_size] = strdup(pathname);
140  ++files_size;
141  if (files_size == 1) {
142  char *ev;
143 
144  ev = getenv("QEMU_NO_CLEANUP");
145  if (ev)
146  no_cleanup = 1;
147  ev = getenv("QEMU_USE_ATEXIT");
148  if (ev)
149  use_atexit = 1;
150  ev = getenv("QEMU_USE_SIGOVERRIDE");
151  if (ev)
152  use_sig_override = 1;
153 
154  if (no_cleanup)
155  ;
156 /*
157  * This way doesn't work; we override sigaction() above.
158  */
159 #if 0
160  else if (use_sig_override) {
161  struct sigaction act;
162  struct sigaction oldact;
163 
164  memset(&act,0,sizeof(act));
165  memset(&oldact,0,sizeof(oldact));
166 
167  act.sa_sigaction = sig_override_handler;
168  act.sa_flags = SA_SIGINFO;
169 
170  sigaction(SIGTERM,&act,&oldact);
171  if (0 && !oldact.sa_sigaction) {
172  free(files[0]);
173  free(files);
174  files = NULL;
175  files_size = 0;
176  goto real;
177  }
178  else
179  qemu_sighandler = oldact.sa_sigaction;
180 
181  if (oldact.sa_sigaction) {
182  act.sa_flags = oldact.sa_flags;
183  act.sa_mask = oldact.sa_mask;
184  }
185 
186  sigaction(SIGINT,&act,NULL);
187  sigaction(SIGHUP,&act,NULL);
188  sigaction(SIGTERM,&act,NULL);
189  }
190 #endif /* 0 */
191  else {
192  real_atexit = dlsym(RTLD_NEXT,"atexit");
193  if (real_atexit)
194  real_atexit(cleanup);
195  }
196  }
197  return 0;
198  }
199 
200  /* real: */
201  if (!real_unlink)
202  real_unlink = dlsym(RTLD_NEXT,"unlink");
203 
204  return real_unlink(pathname);
205 }
206 
207 /*
208  * Wrap mmap to share the mapping instead of privatize it if @fd's
209  * pathname starts with $QEMU_MEMPATH_PREFIX .
210  */
211 void *mmap(void *addr,size_t length,int prot,int flags,int fd,off_t offset) {
212  char *prefix;
213 
214  if (fd <= 0)
215  goto real;
216 
217  prefix = getenv("QEMU_MEMPATH_PREFIX");
218 
219  if (prefix) {
220  char buf[32];
221  char rbuf[256];
222  snprintf(buf,sizeof(buf),"/proc/self/fd/%d",fd);
223  if (readlink(buf,rbuf,sizeof(rbuf)) > 0
224  && strncmp(prefix,rbuf,strlen(prefix)) == 0) {
225  flags &= ~MAP_PRIVATE;
226  flags |= MAP_SHARED;
227  }
228  }
229 
230  real:
231  if (!real_mmap)
232  real_mmap = dlsym(RTLD_NEXT,"mmap");
233  return real_mmap(addr,length,prot,flags,fd,offset);
234 }
char * name
Definition: probe.h:314
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact)
Definition: qemuhacks.c:77
void cleanup()
Definition: dumptarget.c:134
void * mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset)
Definition: qemuhacks.c:211
int unlink(const char *pathname)
Definition: qemuhacks.c:132