changeset 2725:f19d23da7c3e

don't use hsearch_r, use berkeley db and don't leak memory on error.
author Christos Zoulas <christos@zoulas.com>
date Mon, 19 Sep 2011 19:00:27 -0400
parents cfc505a069f9
children 7b0da61aa3af
files agent/src/os/bsd/Makefile agent/src/os/bsd/symtab.c
diffstat 2 files changed, 44 insertions(+), 38 deletions(-) [+]
line wrap: on
line diff
--- a/agent/src/os/bsd/Makefile	Fri Sep 16 15:15:56 2011 -0400
+++ b/agent/src/os/bsd/Makefile	Mon Sep 19 19:00:27 2011 -0400
@@ -32,7 +32,6 @@
 	libproc_impl.c  \
 	ps_proc.c       \
 	ps_core.c       \
-	hsearch_r.c     \
 	BsdDebuggerLocal.c
 
 INCLUDES = -I${JAVA_HOME}/include -I${JAVA_HOME}/include/$(shell uname -s | tr "[:upper:]" "[:lower:]")
--- a/agent/src/os/bsd/symtab.c	Fri Sep 16 15:15:56 2011 -0400
+++ b/agent/src/os/bsd/symtab.c	Mon Sep 19 19:00:27 2011 -0400
@@ -26,7 +26,7 @@
 #include <search.h>
 #include <stdlib.h>
 #include <string.h>
-#include "hsearch_r.h"
+#include <db.h>
 #include "symtab.h"
 #include "salibelf.h"
 
@@ -50,7 +50,7 @@
   char *strs;
   size_t num_symbols;
   struct elf_symbol *symbols;
-  struct hsearch_data *hash_table;
+  DB* hash_table;
 } symtab_t;
 
 // read symbol table from given fd.
@@ -83,8 +83,7 @@
 
   baseaddr = find_base_address(fd, &ehdr);
 
-  scn_cache = (struct elf_section *)
-              calloc(ehdr.e_shnum * sizeof(struct elf_section), 1);
+  scn_cache = calloc(ehdr.e_shnum, sizeof(*scn_cache));
   if (scn_cache == NULL) {
     goto quit;
   }
@@ -94,7 +93,7 @@
     if (cursct->sh_type == SHT_SYMTAB ||
         cursct->sh_type == SHT_STRTAB ||
         cursct->sh_type == SHT_DYNSYM) {
-      if ( (scn_cache[cnt].c_data = read_section_data(fd, &ehdr, cursct)) == NULL) {
+      if ((scn_cache[cnt].c_data = read_section_data(fd, &ehdr, cursct)) == NULL) {
          goto quit;
       }
     }
@@ -116,7 +115,7 @@
 
     if (shdr->sh_type == symsection) {
       ELF_SYM  *syms;
-      int j, n, rslt;
+      int j, n;
       size_t size;
 
       // FIXME: there could be multiple data buffers associated with the
@@ -124,7 +123,7 @@
       // for elf_getdata on Solaris.
 
       // guarantee(symtab == NULL, "multiple symtab");
-      symtab = (struct symtab*)calloc(1, sizeof(struct symtab));
+      symtab = calloc(1, sizeof(*symtab));
       if (symtab == NULL) {
          goto quit;
       }
@@ -134,27 +133,32 @@
       // number of symbols
       n = shdr->sh_size / shdr->sh_entsize;
 
-      // create hash table, we use hcreate_r, hsearch_r and hdestroy_r to
+      // create hash table, we use berkeley db to
       // manipulate the hash table.
-      symtab->hash_table = (struct hsearch_data*) calloc(1, sizeof(struct hsearch_data));
-      rslt = hcreate_r(n, symtab->hash_table);
-      // guarantee(rslt, "unexpected failure: hcreate_r");
+      symtab->hash_table = dbopen(NULL, O_CREAT | O_RDWR, 0600, DB_HASH, NULL);
+      // guarantee(symtab->hash_table, "unexpected failure: dbopen");
+      if (symtab->hash_table == NULL)
+	goto bad;
 
       // shdr->sh_link points to the section that contains the actual strings
       // for symbol names. the st_name field in ELF_SYM is just the
       // string table index. we make a copy of the string table so the
       // strings will not be destroyed by elf_end.
       size = scn_cache[shdr->sh_link].c_shdr->sh_size;
-      symtab->strs = (char *)malloc(size);
+      symtab->strs = malloc(size);
+      if (symtab->strs == NULL)
+	goto bad;
       memcpy(symtab->strs, scn_cache[shdr->sh_link].c_data, size);
 
       // allocate memory for storing symbol offset and size;
       symtab->num_symbols = n;
-      symtab->symbols = (struct elf_symbol *)calloc(n , sizeof(struct elf_symbol));
+      symtab->symbols = calloc(n , sizeof(*symtab->symbols));
+      if (symtab->symbols == NULL)
+	goto bad;
 
       // copy symbols info our symtab and enter them info the hash table
       for (j = 0; j < n; j++, syms++) {
-        ENTRY item, *ret;
+        DBT key, value;
         char *sym_name = symtab->strs + syms->st_name;
 
         // skip non-object and non-function symbols
@@ -168,13 +172,19 @@
         symtab->symbols[j].offset = syms->st_value - baseaddr;
         symtab->symbols[j].size   = syms->st_size;
 
-        item.key = sym_name;
-        item.data = (void *)&(symtab->symbols[j]);
-
-        hsearch_r(item, ENTER, &ret, symtab->hash_table);
+        key.data = sym_name;
+        key.size = strlen(sym_name) + 1;
+        value.data = &(symtab->symbols[j]);
+        value.size = sizeof(void *);
+        (*symtab->hash_table->put)(symtab->hash_table, &key, &value, 0);
       }
     }
   }
+  goto quit;
+
+bad:
+  destroy_symtab(symtab);
+  symtab = NULL;
 
 quit:
   if (shbuf) free(shbuf);
@@ -195,34 +205,31 @@
   if (symtab->strs) free(symtab->strs);
   if (symtab->symbols) free(symtab->symbols);
   if (symtab->hash_table) {
-     hdestroy_r(symtab->hash_table);
-     free(symtab->hash_table);
+    (*symtab->hash_table->close)(symtab->hash_table);
   }
   free(symtab);
 }
 
 uintptr_t search_symbol(struct symtab* symtab, uintptr_t base,
                       const char *sym_name, int *sym_size) {
-  ENTRY item;
-  ENTRY* ret = NULL;
+  DBT key, value;
+  int ret;
 
   // library does not have symbol table
   if (!symtab || !symtab->hash_table)
-     return (uintptr_t)NULL;
+     return 0;
 
-  item.key = (char*) strdup(sym_name);
-  hsearch_r(item, FIND, &ret, symtab->hash_table);
-  if (ret) {
-    struct elf_symbol * sym = (struct elf_symbol *)(ret->data);
+  key.data = (char*)(uintptr_t)sym_name;
+  key.size = strlen(sym_name) + 1;
+  ret = (*symtab->hash_table->get)(symtab->hash_table, &key, &value, 0);
+  if (ret == 0) {
+    struct elf_symbol *sym = value.data;
     uintptr_t rslt = (uintptr_t) ((char*)base + sym->offset);
     if (sym_size) *sym_size = sym->size;
-    free(item.key);
     return rslt;
   }
 
-quit:
-  free(item.key);
-  return (uintptr_t) NULL;
+  return 0;
 }
 
 const char* nearest_symbol(struct symtab* symtab, uintptr_t offset,
@@ -230,12 +237,12 @@
   int n = 0;
   if (!symtab) return NULL;
   for (; n < symtab->num_symbols; n++) {
-     struct elf_symbol* sym = &(symtab->symbols[n]);
-     if (sym->name != NULL &&
-         offset >= sym->offset && offset < sym->offset + sym->size) {
-        if (poffset) *poffset = (offset - sym->offset);
-        return sym->name;
-     }
+    struct elf_symbol* sym = &symtab->symbols[n];
+    if (sym->name != NULL &&
+      offset >= sym->offset && offset < sym->offset + sym->size) {
+      if (poffset) *poffset = (offset - sym->offset);
+      return sym->name;
+    }
   }
   return NULL;
 }