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, 2015 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 && qemu_sigint_handler)
66  qemu_sigint_handler(signal,info,x);
67  if (signal == SIGTERM && qemu_sigterm_handler)
68  qemu_sigterm_handler(signal,info,x);
69  if (signal == SIGHUP && qemu_sighup_handler)
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  if (act) {
111  ouract.sa_mask = act->sa_mask;
112  ouract.sa_flags = act->sa_flags;
113 
114  if (signum == SIGINT)
115  qemu_sigint_handler = act->sa_sigaction;
116  else if (signum == SIGTERM)
117  qemu_sigterm_handler = act->sa_sigaction;
118  else if (signum == SIGHUP)
119  qemu_sighup_handler = act->sa_sigaction;
120  }
121 
122  return real_sigaction(signum,&ouract,oldact);
123  }
124  else
125  goto real;
126 
127  real:
128  return real_sigaction(signum,act,oldact);
129 }
130 
131 /*
132  * Wrap unlink to not unlink if @pathname starts with $QEMU_MEMPATH_PREFIX !
133  */
134 int unlink(const char *pathname) {
135  char *prefix;
136 
137  prefix = getenv("QEMU_MEMPATH_PREFIX");
138  if (prefix && strncmp(prefix,pathname,strlen(prefix)) == 0) {
139  errno = 0;
140  files = realloc(files,files_size + 1);
141  files[files_size] = strdup(pathname);
142  ++files_size;
143  if (files_size == 1) {
144  char *ev;
145 
146  ev = getenv("QEMU_NO_CLEANUP");
147  if (ev)
148  no_cleanup = 1;
149  ev = getenv("QEMU_USE_ATEXIT");
150  if (ev)
151  use_atexit = 1;
152  ev = getenv("QEMU_USE_SIGOVERRIDE");
153  if (ev)
154  use_sig_override = 1;
155 
156  if (no_cleanup)
157  ;
158 /*
159  * This way doesn't work; we override sigaction() above.
160  */
161 #if 0
162  else if (use_sig_override) {
163  struct sigaction act;
164  struct sigaction oldact;
165 
166  memset(&act,0,sizeof(act));
167  memset(&oldact,0,sizeof(oldact));
168 
169  act.sa_sigaction = sig_override_handler;
170  act.sa_flags = SA_SIGINFO;
171 
172  sigaction(SIGTERM,&act,&oldact);
173  if (0 && !oldact.sa_sigaction) {
174  free(files[0]);
175  free(files);
176  files = NULL;
177  files_size = 0;
178  goto real;
179  }
180  else
181  qemu_sighandler = oldact.sa_sigaction;
182 
183  if (oldact.sa_sigaction) {
184  act.sa_flags = oldact.sa_flags;
185  act.sa_mask = oldact.sa_mask;
186  }
187 
188  sigaction(SIGINT,&act,NULL);
189  sigaction(SIGHUP,&act,NULL);
190  sigaction(SIGTERM,&act,NULL);
191  }
192 #endif /* 0 */
193  else {
194  real_atexit = dlsym(RTLD_NEXT,"atexit");
195  if (real_atexit)
196  real_atexit(cleanup);
197  }
198  }
199  return 0;
200  }
201 
202  /* real: */
203  if (!real_unlink)
204  real_unlink = dlsym(RTLD_NEXT,"unlink");
205 
206  return real_unlink(pathname);
207 }
208 
209 /*
210  * Wrap mmap to share the mapping instead of privatize it if @fd's
211  * pathname starts with $QEMU_MEMPATH_PREFIX .
212  */
213 void *mmap(void *addr,size_t length,int prot,int flags,int fd,off_t offset) {
214  char *prefix;
215 
216  if (fd <= 0)
217  goto real;
218 
219  prefix = getenv("QEMU_MEMPATH_PREFIX");
220 
221  if (prefix) {
222  char buf[32];
223  char rbuf[256];
224  snprintf(buf,sizeof(buf),"/proc/self/fd/%d",fd);
225  if (readlink(buf,rbuf,sizeof(rbuf)) > 0
226  && strncmp(prefix,rbuf,strlen(prefix)) == 0) {
227  flags &= ~MAP_PRIVATE;
228  flags |= MAP_SHARED;
229  }
230  }
231 
232  real:
233  if (!real_mmap)
234  real_mmap = dlsym(RTLD_NEXT,"mmap");
235  return real_mmap(addr,length,prot,flags,fd,offset);
236 }
char * name
Definition: probe.h:314
static uint64_t unsigned int i
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact)
Definition: qemuhacks.c:77
void free(void *ptr)
Definition: debugserver.c:207
void * mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset)
Definition: qemuhacks.c:213
void * realloc(void *ptr, size_t size)
Definition: debugserver.c:221
int unlink(const char *pathname)
Definition: qemuhacks.c:134
void cleanup()
Definition: debugserver.c:295