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
binfile.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013 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 <stdlib.h>
20 #include <unistd.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <fcntl.h>
24 #include <errno.h>
25 #include <string.h>
26 #include <stdint.h>
27 #include <inttypes.h>
28 #include <assert.h>
29 
30 #include "config.h"
31 #include "common.h"
32 #include "log.h"
33 #include "output.h"
34 #include "binfile.h"
35 #include "dwdebug.h"
36 #include "dwdebug_priv.h"
37 
38 #include <dwarf.h>
39 #include <gelf.h>
40 #include <elfutils/libebl.h>
41 #include <elfutils/libdw.h>
42 #include <elfutils/libdwfl.h>
43 
44 #include "memory-access.h"
45 
46 
47 /* binary filename to debug filename */
48 static GHashTable *binfile_tab = NULL;
49 
50 /*
51  * For now, only an ELF backend.
52  */
53 extern struct binfile_ops elf_binfile_ops;
54 
57  NULL,
58 };
59 
60 static char *LIBFORMAT1 = "([\\w\\d_\\.\\-]+[\\w\\d]).so.([\\d\\.]+)";
61 static char *LIBFORMAT2 = "([\\w\\d_\\.\\-]+[\\w\\d]).so";
62 static regex_t LIBREGEX1;
63 static regex_t LIBREGEX2;
64 
65 static int init_done = 0;
66 
67 /*
68  * Helpers.
69  */
70 static int _filename_info(char *filename,
71  char **realfilename,char **name,char **version);
72 
73 /*
74  * Lib init/fini stuff.
75  */
76 static void binfile_fini(void) {
77  GHashTableIter iter;
78  struct binfile *binfile;
79 
80  if (!init_done)
81  return;
82 
83  if (binfile_tab) {
84  while (g_hash_table_size(binfile_tab)) {
85  g_hash_table_iter_init(&iter,binfile_tab);
86  while (g_hash_table_iter_next(&iter,NULL,(gpointer)&binfile)) {
87  binfile_free(binfile,1);
88  break;
89  }
90  }
91  g_hash_table_destroy(binfile_tab);
92  binfile_tab = NULL;
93  }
94 
95  regfree(&LIBREGEX1);
96  memset(&LIBREGEX1,0,sizeof(LIBREGEX1));
97  regfree(&LIBREGEX2);
98  memset(&LIBREGEX2,0,sizeof(LIBREGEX2));
99 
100  init_done = 0;
101 }
102 
103 void binfile_init(void) {
104  if (init_done)
105  return;
106 
107  atexit(binfile_fini);
108 
109  if (regcomp(&LIBREGEX1,LIBFORMAT1,REG_EXTENDED)) {
110  verror("regcomp('%s'): %s\n",LIBFORMAT1,strerror(errno));
111  assert(0);
112  }
113  if (regcomp(&LIBREGEX2,LIBFORMAT2,REG_EXTENDED)) {
114  verror("regcomp('%s'): %s\n",LIBFORMAT2,strerror(errno));
115  assert(0);
116  }
117 
118  binfile_tab = g_hash_table_new_full(g_str_hash,g_str_equal,
119  NULL,NULL);
120 
121  init_done = 1;
122 }
123 
124 struct binfile *binfile_create(char *filename,struct binfile_ops *bfops,
125  void *priv) {
126  struct binfile *binfile;
127  struct symbol_root_elf *sre;
128 
129  binfile = (struct binfile *)calloc(1,sizeof(*binfile));
130  binfile->fd = -1;
131  binfile->type = BINFILE_TYPE_NONE;
132  binfile->ops = bfops;
133  binfile->priv = priv;
134 
135  /*
136  * Try to resolve the realpath, and extract some infor from the
137  * filename. Use the real path as @binfile->filename if it is
138  * different than @filename.
139  */
140  binfile->filename = NULL;
141  if (_filename_info(filename,&binfile->filename,
142  &binfile->name,&binfile->version)) {
143  free(binfile);
144  return NULL;
145  }
146  else if (binfile->filename == filename)
147  binfile->filename = strdup(filename);
148 
149  binfile->root =
151  LOADTYPE_FULL,NULL);
152  sre = calloc(1,sizeof(*sre));
153  sre->binfile = binfile;
154  symbol_set_root_priv(binfile->root,sre);
155  RHOLD(binfile->root,binfile);
156  symbol_write_owned_scope(binfile->root);
157  binfile->ranges = clrange_create();
158 
159  return binfile;
160 }
161 
162 struct binfile *binfile_lookup(char *filename) {
163  char *realname = filename;
164  struct binfile *retval = NULL;
165 
166  if (_filename_info(filename,&realname,NULL,NULL)) {
167  /*
168  * Just fail silently for now; the binfile_create will fail too!
169  */
170  return NULL;
171  }
172 
173  retval = (struct binfile *)g_hash_table_lookup(binfile_tab,realname);
174  if (realname != filename)
175  free(realname);
176 
177  return retval;
178 }
179 
180 int binfile_cache(struct binfile *binfile) {
181  if (g_hash_table_lookup(binfile_tab,binfile->filename)) {
182  vwarn("binfile %s already cached; not caching!\n",binfile->filename);
183  return -1;
184  }
185  g_hash_table_insert(binfile_tab,(gpointer)binfile->filename,(gpointer)binfile);
186  return 0;
187 }
188 
189 int binfile_uncache(struct binfile *binfile) {
190  if (g_hash_table_lookup(binfile_tab,binfile->filename) != binfile)
191  return 0;
192  g_hash_table_remove(binfile_tab,(gpointer)binfile->filename);
193 
194  return 0;
195 }
196 
198  GHashTableIter iter;
199  struct binfile *binfile;
200  int retval = 0;
201 
202  /*
203  * One binfile_free may invoke another, so loop this way so we don't
204  * mess up the iterator. Ugh.
205  */
206  while (g_hash_table_size(binfile_tab)) {
207  g_hash_table_iter_init(&iter,binfile_tab);
208  while (g_hash_table_iter_next(&iter,NULL,(gpointer)&binfile)) {
209  if (binfile->refcnt <= 0) {
210  ++retval;
211  binfile_free(binfile,0);
212  }
213  }
214  }
215 
216  return retval;
217 }
218 
220  char *root_prefix,
221  ADDR base,GHashTable *config) {
222  struct binfile *bf;
223  struct binfile_instance *bfi;
224 
225  /*
226  * We cache a shareable version of the binfile, and then create the
227  * private, per-instance copy with the next call.
228  */
229  if (!(bf = binfile_open(filename,root_prefix,NULL))) {
230  verror("could not build instance from %s!\n",filename);
231  return NULL;
232  }
233 
234  if (!(bfi = bf->ops->infer_instance(bf,base,config))) {
235  verror("could not build instance from binfile %s!\n",bf->filename);
236  return NULL;
237  }
238 
239  return bfi;
240 }
241 
243  char *root_prefix,
244  ADDR base,GHashTable *config) {
245  struct binfile_instance *retval;
246 
247  retval = binfile_infer_instance__int(filename,root_prefix,base,config);
248  if (retval)
249  RHOLD(retval,retval);
250 
251  return retval;
252 }
253 
254 struct binfile *binfile_open__int(char *filename,char *root_prefix,
255  struct binfile_instance *bfinst) {
256  struct binfile *retval = NULL;
257  struct binfile_ops **ops;
258 
259  if (bfinst) {
261  "using %s backend (from instance) for file %s\n",
262  bfinst->ops->get_backend_name(),filename);
263  return bfinst->ops->open(filename,root_prefix,bfinst);
264  }
265  else if ((retval = binfile_lookup(filename))) {
266  return retval;
267  }
268 
269  ops = &binfile_types[0];
270  while (*ops) {
271  vdebug(2,LA_DEBUG,LF_BFILE,"trying %s backend for file %s\n",
272  (*ops)->get_backend_name(),filename);
273  retval = (*ops)->open(filename,root_prefix,bfinst);
274  if (retval) {
275  if (!retval->instance) {
276  binfile_cache(retval);
277  }
278  return retval;
279  }
280  ++ops;
281  }
282 
283  return NULL;
284 }
285 
286 struct binfile *binfile_open(char *filename,char *root_prefix,
287  struct binfile_instance *bfinst) {
288  struct binfile *retval;
289 
290  retval = binfile_open__int(filename,root_prefix,bfinst);
291  if (retval)
292  RHOLD(retval,retval);
293 
294  return retval;
295 }
296 
297 struct binfile *binfile_open_debuginfo__int(struct binfile *binfile,
298  struct binfile_instance *bfinst,
299  const char *DFPATH[]) {
300  if (binfile->ops->open_debuginfo)
301  return binfile->ops->open_debuginfo(binfile,bfinst,DFPATH);
302 
303  return NULL;
304 }
305 
306 struct binfile *binfile_open_debuginfo(struct binfile *binfile,
307  struct binfile_instance *bfinst,
308  const char *DFPATH[]) {
309  struct binfile *retval;
310 
311  retval = binfile_open_debuginfo__int(binfile,bfinst,DFPATH);
312  if (retval)
313  RHOLD(retval,retval);
314 
315  return retval;
316 }
317 
318 const char *binfile_get_backend_name(struct binfile *binfile) {
319  return binfile->ops->get_backend_name();
320 }
321 
322 binfile_type_t binfile_get_binfile_type(struct binfile *binfile) {
323  return binfile->type;
324 }
325 
326 int binfile_get_root_scope_sizes(struct binfile *binfile,
327  int *named,int *duplicated,int *anon,
328  int *numscopes) {
329  struct scope *scope;
330 
331  if (!binfile->root)
332  return -1;
333  scope = symbol_read_owned_scope(binfile->root);
334  if (!scope)
335  return -1;
336  return scope_get_sizes(scope,named,duplicated,anon,numscopes);
337 }
338 
339 int binfile_close(struct binfile *binfile) {
340  int retval;
341 
342  if (binfile->fd < 0 && !binfile->image) {
343  errno = EINVAL;
344  return -1;
345  }
346 
347  retval = binfile->ops->close(binfile);
348 
349  return retval;
350 }
351 
352 REFCNT binfile_release(struct binfile *binfile) {
353  REFCNT refcnt;
354  RPUT(binfile,binfile,binfile,refcnt);
355  return refcnt;
356 }
357 
358 REFCNT binfile_free(struct binfile *binfile,int force) {
359  REFCNT retval = binfile->refcnt;
360  REFCNT trefcnt;
361 
362  if (retval) {
363  if (!force) {
364  verror("cannot free (%d refs) binfile(%s)\n",
365  retval,binfile->filename);
366  return retval;
367  }
368  else {
369  vwarn("forced free (%d refs) binfile(%s)\n",
370  retval,binfile->filename);
371  }
372  }
373 
374  vdebug(5,LA_DEBUG,LF_BFILE,"freeing binfile(%s)\n",binfile->filename);
375 
376  /*
377  * Only remove it if the value matches us. This is necessary
378  * because if we loaded binfile against an instance, and there were
379  * relocations, this binfile will not be in the hashtable -- but
380  * another binfile (that was NOT relocated!) could still be in the
381  * hashtable. :)
382  */
383  if (g_hash_table_lookup(binfile_tab,binfile->filename) == binfile)
384  g_hash_table_remove(binfile_tab,binfile->filename);
385 
386  if (binfile->fd > -1 || binfile->image)
387  binfile_close(binfile);
388 
389  if (binfile->instance) {
390  RPUT(binfile->instance,binfile_instance,binfile,trefcnt);
391  binfile->instance = NULL;
392  }
393 
394  binfile->ops->free(binfile);
395 
396  if (binfile->ranges) {
397  clrange_free(binfile->ranges);
398  binfile->ranges = NULL;
399  }
400  if (binfile->root) {
401  RPUT(binfile->root,symbol,binfile,trefcnt);
402  }
403  if (binfile->dynstrtab) {
404  free(binfile->dynstrtab);
405  binfile->dynstrtab = NULL;
406  binfile->dynstrtablen = 0;
407  }
408  if (binfile->strtab) {
409  free(binfile->strtab);
410  binfile->strtab = NULL;
411  binfile->strtablen = 0;
412  }
413  if (binfile->name) {
414  free(binfile->name);
415  binfile->name = NULL;
416  }
417  if (binfile->version) {
418  free(binfile->version);
419  binfile->version = NULL;
420  }
421  if (binfile->filename) {
422  free(binfile->filename);
423  binfile->filename = NULL;
424  }
425 
426  free(binfile);
427 
428  return retval;
429 }
430 
432  REFCNT refcnt;
433  RPUT(bfi,binfile_instance,bfi,refcnt);
434  return refcnt;
435 }
436 
438  REFCNT retval = bfi->refcnt;
439 
440  if (retval) {
441  if (!force) {
442  verror("cannot free (%d refs) binfile_instance(%s)\n",
443  retval,bfi->filename);
444  return retval;
445  }
446  else {
447  vwarn("forced free (%d refs) binfile_instance(%s)\n",
448  retval,bfi->filename);
449  }
450  }
451 
452  vdebug(5,LA_DEBUG,LF_BFILE,"freeing binfile_instance(%s)\n",bfi->filename);
453 
454  bfi->ops->free_instance(bfi);
455 
456  if (bfi->filename) {
457  free(bfi->filename);
458  bfi->filename = NULL;
459  }
460  free(bfi);
461 
462  return retval;
463 }
464 
465 static int _filename_info(char *filename,
466  char **realfilename,char **name,char **version) {
467  regmatch_t matches[2];
468  int match_len;
469  char *realname;
470  struct stat sbuf;
471 
472  realname = realpath(filename,NULL);
473  if (realname && strcmp(realname,filename) == 0) {
474  free(realname);
475  realname = filename;
476  }
477  else if (!realname) {
478  verror("realpath(%s): %s\n",filename,strerror(errno));
479  return -1;
480  }
481 
482  if (stat(realname,&sbuf) < 0) {
483  verror("stat(%s): %s\n",realname,strerror(errno));
484  if (realname != filename)
485  free(realname);
486  return -1;
487  }
488 
489  if (realfilename)
490  *realfilename = realname;
491 
492  if (!name && !version)
493  return 0;
494 
495  if (regexec(&LIBREGEX1,realname,2,matches,0) == 0) {
496  if (name) {
497  match_len = matches[0].rm_eo - matches[0].rm_so;
498  *name = malloc(match_len + 1);
499  memcpy(*name,realname + matches[0].rm_so,match_len);
500  *name[match_len] = '\0';
501  }
502 
503  if (version) {
504  match_len = matches[1].rm_eo - matches[1].rm_so;
505  *version = malloc(match_len + 1);
506  memcpy(*name,realname + matches[1].rm_so,match_len);
507  *version[match_len] = '\0';
508  }
509  }
510  else if (regexec(&LIBREGEX2,realname,1,matches,0) == 0) {
511  if (name) {
512  match_len = matches[0].rm_eo - matches[0].rm_so;
513  *name = malloc(match_len + 1);
514  memcpy(*name,realname + matches[0].rm_so,match_len);
515  *name[match_len] = '\0';
516  }
517 
518  if (version) {
519  *version = NULL;
520  vwarn("cannot extract version from %s!\n",realname);
521  }
522  }
523 
524  return 0;
525 }
REFCNT binfile_instance_release(struct binfile_instance *bfi)
Definition: binfile.c:431
struct scope * symbol_write_owned_scope(struct symbol *symbol)
Definition: debug.c:2689
char * filename
Definition: binfile.h:243
struct binfile_instance * binfile_infer_instance(char *filename, char *root_prefix, ADDR base, GHashTable *config)
Definition: binfile.c:242
Definition: log.h:136
REFCNT binfile_free(struct binfile *binfile, int force)
Definition: binfile.c:358
int fd
Definition: binfile.h:214
void binfile_init(void)
Definition: binfile.c:103
clrange_t ranges
Definition: binfile.h:279
struct symbol * symbol_create(symbol_type_t symtype, symbol_source_t source, char *name, int name_copy, SMOFFSET offset, load_type_t loadtype, struct scope *scope)
Definition: debug.c:2550
struct scope * symbol_read_owned_scope(struct symbol *symbol)
Definition: debug.c:2674
char * version
Definition: binfile.h:259
char * image
Definition: binfile.h:213
binfile_type_t type
Definition: binfile.h:200
struct binfile * binfile_open_debuginfo(struct binfile *binfile, struct binfile_instance *bfinst, const char *DFPATH[])
Definition: binfile.c:306
unsigned int strtablen
Definition: binfile.h:224
char * strtab
Definition: binfile.h:225
unsigned int dynstrtablen
Definition: binfile.h:233
struct binfile * binfile
void(* free)(struct binfile *bfile)
Definition: binfile.h:182
#define assert(x)
Definition: dlmalloc.c:1456
struct binfile_instance * binfile_infer_instance__int(char *filename, char *root_prefix, ADDR base, GHashTable *config)
Definition: binfile.c:219
#define verror(format,...)
Definition: log.h:30
struct binfile * binfile_lookup(char *filename)
Definition: binfile.c:162
struct binfile * binfile_open(char *filename, char *root_prefix, struct binfile_instance *bfinst)
Definition: binfile.c:286
struct binfile * binfile_open_debuginfo__int(struct binfile *binfile, struct binfile_instance *bfinst, const char *DFPATH[])
Definition: binfile.c:297
#define vwarn(format,...)
Definition: log.h:33
REFCNT binfile_instance_free(struct binfile_instance *bfi, int force)
Definition: binfile.c:437
void free(void *ptr)
Definition: debugserver.c:207
char * root_prefix
Definition: binfile.h:376
void clrange_free(clrange_t clf)
Definition: clfit.c:572
int(* close)(struct binfile *bfile)
Definition: binfile.h:181
Definition: log.h:69
char * name
Definition: binfile.h:258
void * priv
Definition: binfile.h:265
struct symbol * root
Definition: binfile.h:272
const char *(* get_backend_name)(void)
Definition: binfile.h:173
struct binfile * binfile_open__int(char *filename, char *root_prefix, struct binfile_instance *bfinst)
Definition: binfile.c:254
REFCNT refcnt
Definition: dwdebug_priv.h:455
binfile_type_t binfile_get_binfile_type(struct binfile *binfile)
Definition: binfile.c:322
int binfile_cache(struct binfile *binfile)
Definition: binfile.c:180
binfile_type_t
Definition: binfile.h:31
int binfile_uncache(struct binfile *binfile)
Definition: binfile.c:189
struct binfile_ops elf_binfile_ops
Definition: binfile_elf.c:67
#define RHOLD(x, hx)
Definition: common.h:622
#define vdebug(devel, areas, flags, format,...)
Definition: log.h:302
struct binfile *(* open)(char *filename, char *root_prefix, struct binfile_instance *bfinst)
Definition: binfile.h:174
struct binfile * binfile_create(char *filename, struct binfile_ops *bfops, void *priv)
Definition: binfile.c:124
struct binfile_ops * ops
Definition: binfile.h:264
struct binfile *(* open_debuginfo)(struct binfile *binfile, struct binfile_instance *bfinst, const char *DFPATH[])
Definition: binfile.h:176
void * calloc(size_t nmemb, size_t size)
Definition: debugserver.c:200
int binfile_cache_clean(void)
Definition: binfile.c:197
REFCNT refcnt
Definition: binfile.h:366
REFCNT binfile_release(struct binfile *binfile)
Definition: binfile.c:352
const char * binfile_get_backend_name(struct binfile *binfile)
Definition: binfile.c:318
struct binfile_ops * ops
Definition: binfile.h:381
int scope_get_sizes(struct scope *scope, int *named, int *duplicated, int *anon, int *numscopes)
Definition: scope.c:263
uint32_t ADDR
Definition: common.h:64
struct binfile_instance *(* infer_instance)(struct binfile *binfile, ADDR base, GHashTable *config)
Definition: binfile.h:179
int symbol_set_root_priv(struct symbol *symbol, void *priv)
Definition: debug.c:3288
uint32_t REFCNT
Definition: common.h:124
struct binfile_instance * instance
Definition: binfile.h:301
void(* free_instance)(struct binfile_instance *bfi)
Definition: binfile.h:183
int binfile_get_root_scope_sizes(struct binfile *binfile, int *named, int *duplicated, int *anon, int *numscopes)
Definition: binfile.c:326
char * dynstrtab
Definition: binfile.h:234
int binfile_close(struct binfile *binfile)
Definition: binfile.c:339
char * root_prefix
Definition: binfile.h:321
#define RPUT(x, objtype, hx, rc)
Definition: common.h:624
void * malloc(size_t size)
Definition: debugserver.c:214
REFCNT refcnt
Definition: binfile.h:196
struct binfile_ops * binfile_types[]
Definition: binfile.c:55
struct spf_config * config
Definition: spf.c:156
char * filename
Definition: binfile.h:368
clrange_t clrange_create(void)
Definition: clfit.c:27