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
debugserver.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 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 <stdio.h>
20 #include <string.h>
21 #include <errno.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <unistd.h>
25 #include <sys/mman.h>
26 #include <fcntl.h>
27 #include <signal.h>
28 #include <sys/user.h>
29 
30 #include "log.h"
31 #include "dwdebug.h"
32 #include "dlmalloc.h"
33 
77 /*
78  * Implementation:
79  *
80  * It was surprisingly hard to figure out how to do this. Right away,
81  * the obviously method is to create a shared memory segment (whichever
82  * way), and restrict malloc to the segment. There doesn't appear to be
83  * any software that does this (and believe me, I've looked many times
84  * --- Ralf Engelschall's `mm' library is probably closest, but it has
85  * an apparently arbitrary 64MB soft limit).
86  *
87  * Anyway, it turned out to be easiest to grab the latest Doug Lea
88  * malloc (2.8.6), because it allows you to define an mspace with a
89  * fixed base address, and provide your own morecore function. So, we
90  * use the POSIX shared memory strategy (shm_open, ftruncate, mmap), but
91  * I added ftruncate as my morecore strategy, and build dlmalloc
92  * accordingly. Then (once we are initialized!!!) we use mspaces to
93  * restrict memory operations to our mspace. We create a mspace ASAP,
94  * but there is still some malloc'ing going on using the heap (sbrk --
95  * my malloc wrappers and morecore will just call the regular dlmalloc
96  * (non-mspace) functions, and use sbrk (I disable mmap as a strategy),
97  * until we've initialized the fixed-base mspace. We create an mspace
98  * at a "safe" offset that provides us enough room to fully load the
99  * debugfile (we use the db file to guess at a hole, and estimate based
100  * on debuginfo file size how much space we'll need). Also, if
101  * ftruncate fails during alloc/free, that's it --- we abort.
102  * Technically, we could switch back to the non-mspace dlmalloc at any
103  * time, but there's no need.
104  *
105  * Because the whole goal of the debugserver is to share full,
106  * in-memory, dynamically-allocated data structures with other
107  * processes, it must publish metadata telling these client processes
108  * where to mmap the shm segment. For now, debugservers are
109  * root-privilege only, and keep metadata in /var/lib/vmi/debugserver.db
110  * (which is edited safely by multiple instances of a debugserver via
111  * flock). Eventually, we'll
112  * debugservers edit/create the /var/lib/vmi/debugserver.db file ;
113  * however, you can specify a separate db file if desired --- and this
114  * may be 1) necessary if you are not root; and/or 2) desirable if you
115  * want to control
116  */
117 
118 /*
119  * Our malloc wrappers --- just call the dl mspace_* functions with our
120  * mspace. If the mspace hasn't been initialized, the default dl malloc
121  * strategy gets used.
122  */
123 
124 #define MADDR 0x100000000
125 
126 static char shm_mm_name[NAME_MAX];
127 static int shm_mm_on = 0;
128 static int shm_mm_fd = -1;
129 static off_t shm_mm_length = 0;
130 static void *shm_mm_base = (void *)0;
131 static mspace global_mspace;
132 
133 /*
134  * Our MoreCore function for shm.
135  */
136 void *shm_morecore(int size) {
137 
138  printf("morecore: %d\n",size);
139 
140  /* If we're not initialized yet, let sbrk handle it. */
141  if (!shm_mm_base || shm_mm_fd < 0)
142  return sbrk(size);
143 
144  /* Conform. */
145  if (!size) {
146  printf("morecore: ret 0x%lx\n",(uintptr_t)(shm_mm_base + shm_mm_length + 1));
147  return (shm_mm_base + shm_mm_length + 1);
148  }
149 
150  if (ftruncate(shm_mm_fd,shm_mm_length + size)) {
151  verror("ftruncate: %s\n",strerror(errno));
152  errno = ENOMEM;
153  return (void *)MFAIL;
154  }
155  else if (mremap(shm_mm_base,shm_mm_length,shm_mm_length + size,0)
156  != shm_mm_base) {
157  verror("mremap: %s\n",strerror(errno));
158  errno = ENOMEM;
159  return (void *)MFAIL;
160  }
161  else {
162  shm_mm_length += size;
163  errno = 0;
164  printf("morecore: ret 0x%lx (0x%lx,0x%lx)\n",
165  (uintptr_t)(shm_mm_base + shm_mm_length - size + 1),
166  (uintptr_t)shm_mm_base,(uintptr_t)shm_mm_length);
167  return (shm_mm_base + shm_mm_length - size + 1);
168  }
169 }
170 
171 int shm_init(char *name,off_t size) {
172  shm_mm_fd = shm_open(name,O_CREAT | O_EXCL | O_RDWR,
173  S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
174  if (shm_mm_fd < 0)
175  return -1;
176 
177  if (ftruncate(shm_mm_fd,size)) {
178  shm_unlink(shm_mm_name);
179  shm_mm_fd = -1;
180  return -1;
181  }
182 
183  if (mmap((void *)MADDR,size,PROT_READ | PROT_WRITE,MAP_SHARED | MAP_FIXED,
184  shm_mm_fd,0) != (void *)MADDR) {
185  shm_unlink(shm_mm_name);
186  shm_mm_fd = -1;
187  return -1;
188  }
189 
190  shm_mm_base = (void *)MADDR;
191  shm_mm_length = size;
192  strncpy(shm_mm_name,name,NAME_MAX);
193  shm_mm_name[NAME_MAX - 1] = '\0';
194  global_mspace = create_mspace_with_base(shm_mm_base,shm_mm_length,0);
195  shm_mm_on = 1;
196 
197  return 0;
198 }
199 
200 void *calloc(size_t nmemb,size_t size) {
201  if (!shm_mm_on)
202  return dlcalloc(nmemb,size);
203  else
204  return mspace_calloc(global_mspace,nmemb,size);
205 }
206 
207 void free(void *ptr) {
208  if (!shm_mm_on)
209  return dlfree(ptr);
210  else
211  return mspace_free(global_mspace,ptr);
212 }
213 
214 void *malloc(size_t size) {
215  if (!shm_mm_on)
216  return dlmalloc(size);
217  else
218  return mspace_malloc(global_mspace,size);
219 }
220 
221 void *realloc(void *ptr,size_t size) {
222  if (!shm_mm_on)
223  return dlrealloc(ptr,size);
224  else
225  return mspace_realloc(global_mspace,ptr,size);
226 }
227 
228 void *memalign(size_t alignment,size_t size) {
229  if (!shm_mm_on)
230  return dlmemalign(alignment,size);
231  else
232  return mspace_memalign(global_mspace,alignment,size);
233 }
234 
235 int posix_memalign(void **memptr,size_t alignment,size_t size) {
236  if (!shm_mm_on)
237  return dlposix_memalign(memptr,alignment,size);
238  else
239  return mspace_posix_memalign(global_mspace,memptr,alignment,size);
240 }
241 
242 void *valloc(size_t size) {
243  if (!shm_mm_on)
244  return dlvalloc(size);
245  else
246  return mspace_memalign(global_mspace,PAGE_SIZE,size);
247 }
248 
249 void *pvalloc(size_t size) {
250  if (!shm_mm_on)
251  return dlpvalloc(size);
252  else {
253  size_t rsize = (size + PAGE_SIZE - (size_t)1) & ~(PAGE_SIZE - (size_t)1);
254  return mspace_memalign(global_mspace,PAGE_SIZE,rsize);
255  }
256 }
257 
258 struct mallinfo mallinfo(void) {
259  if (!shm_mm_on)
260  return dlmallinfo();
261  else
262  return mspace_mallinfo(global_mspace);
263 }
264 
265 int mallopt(int param,int value) {
266  if (!shm_mm_on)
267  return dlmallopt(param,value);
268  else
269  /* XXX: weird, no mspace first arg? */
270  return mspace_mallopt(param,value);
271 }
272 
273 int malloc_trim(size_t pad) {
274  if (!shm_mm_on)
275  return dlmalloc_trim(pad);
276  else
277  return mspace_trim(global_mspace,pad);
278 }
279 
280 void malloc_stats(void) {
281  if (!shm_mm_on)
282  return dlmalloc_stats();
283  else
284  return mspace_malloc_stats(global_mspace);
285 }
286 
287 size_t malloc_usable_size(void *ptr) {
288  if (!shm_mm_on)
289  return dlmalloc_usable_size(ptr);
290  else
291  /* XXX: no mspace-specific version? */
292  return mspace_usable_size((const void *)ptr);
293 }
294 
295 void cleanup() {
296  dwdebug_fini();
297  munmap((void *)MADDR,shm_mm_length);
298  shm_unlink(shm_mm_name);
299  exit(0);
300 }
301 
302 void sigh(int signo) {
303  cleanup();
304 }
305 
306 int main(int argc,char **argv) {
307  struct stat sbuf;
308  struct debugfile *debugfile;
309  char sname[NAME_MAX];
310  char *cptr;
311 
312  if (argc < 1) {
313  verror("Must supply a debugfile pathname!\n");
314  exit(-1);
315  }
316 
317  if (geteuid() != 0) {
318  verror("must be root!\n");
319  exit(-1);
320  }
321 
322  if (stat("/var/lib/vmi",&sbuf) && mkdir("/var/lib/vmi",0)) {
323  verror("could not create /var/lib/vmi: %s\n",strerror(errno));
324  exit(-1);
325  }
326 
327  signal(SIGINT,sigh);
328  signal(SIGHUP,sigh);
329 
330  strncpy(sname,argv[1],NAME_MAX);
331  sname[NAME_MAX - 1] = '\0';
332 
333  /* POSIX shm names can't have '/' */
334  for (cptr = sname; *cptr != '\0'; ++cptr)
335  if (*cptr == '/')
336  *cptr = '|';
337 
338  if (shm_init(sname,4096)) {
339  verror("Could not initialize shm-backed heap: %s\n",strerror(errno));
340  exit(-1);
341  }
342 
343  dwdebug_init();
344  atexit(dwdebug_fini);
345 
346  debugfile = debugfile_from_file(argv[1],NULL,NULL);
347  if (!debugfile) {
348  cleanup();
349  exit(-8);
350  }
351 
352  printf("shm_base = 0x%lx, shm_length = 0x%lx, debugfile = 0x%lx ...\n",
353  (uintptr_t)shm_mm_base,(uintptr_t)shm_mm_length,(uintptr_t)debugfile);
354 
355  while (1)
356  sleep(32768);
357 
358  return 0;
359 }
#define dlpvalloc
Definition: dlmalloc.c:824
#define dlmalloc
Definition: dlmalloc.c:818
#define dlmemalign
Definition: dlmalloc.c:819
struct debugfile * debugfile_from_file(char *filename, char *root_prefix, struct array_list *debugfile_load_opts_list)
Definition: debug.c:1584
#define dlmallinfo
Definition: dlmalloc.c:825
int shm_init(char *name, off_t size)
Definition: debugserver.c:171
#define dlcalloc
Definition: dlmalloc.c:816
#define dlposix_memalign
Definition: dlmalloc.c:820
#define dlvalloc
Definition: dlmalloc.c:823
int mallopt(int param, int value)
Definition: debugserver.c:265
#define MFAIL
Definition: dlmalloc.c:1639
int malloc_trim(size_t pad)
Definition: debugserver.c:273
#define verror(format,...)
Definition: log.h:30
void * memalign(size_t alignment, size_t size)
Definition: debugserver.c:228
void * shm_morecore(int size)
Definition: debugserver.c:136
#define dlrealloc
Definition: dlmalloc.c:821
void dwdebug_init(void)
Definition: debug.c:83
void free(void *ptr)
Definition: debugserver.c:207
void sigh(int signo)
Definition: debugserver.c:302
#define MADDR
Definition: debugserver.c:124
void dwdebug_fini(void)
Definition: debug.c:143
int main(int argc, char **argv)
Definition: debugserver.c:306
#define dlmallopt
Definition: dlmalloc.c:826
void malloc_stats(void)
Definition: debugserver.c:280
void * mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset)
Definition: qemuhacks.c:213
#define dlmalloc_stats
Definition: dlmalloc.c:828
#define PROT_WRITE
Definition: common.h:107
int posix_memalign(void **memptr, size_t alignment, size_t size)
Definition: debugserver.c:235
void * valloc(size_t size)
Definition: debugserver.c:242
void * realloc(void *ptr, size_t size)
Definition: debugserver.c:221
void * calloc(size_t nmemb, size_t size)
Definition: debugserver.c:200
size_t malloc_usable_size(void *ptr)
Definition: debugserver.c:287
#define PAGE_SIZE
#define dlfree
Definition: dlmalloc.c:817
#define dlmalloc_trim
Definition: dlmalloc.c:827
#define PROT_READ
Definition: common.h:106
#define dlmalloc_usable_size
Definition: dlmalloc.c:829
void * malloc(size_t size)
Definition: debugserver.c:214
void * pvalloc(size_t size)
Definition: debugserver.c:249
void cleanup()
Definition: debugserver.c:295