don't use hsearch_r, use berkeley db and don't leak memory on error.
authorChristos Zoulas <christos@zoulas.com>
Mon Sep 19 19:00:27 2011 -0400 (20 months ago)
changeset 2725f19d23da7c3e
parent 2724cfc505a069f9
child 27277b0da61aa3af
don't use hsearch_r, use berkeley db and don't leak memory on error.
agent/src/os/bsd/Makefile
agent/src/os/bsd/symtab.c
--- 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 @@ SOURCES = salibelf.c \
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 @@ typedef struct symtab {
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 @@ struct symtab* build_symtab(int fd) {
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 @@ struct symtab* build_symtab(int fd) {
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 @@ struct symtab* build_symtab(int fd) {
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 @@ struct symtab* build_symtab(int fd) {
// 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 @@ struct symtab* build_symtab(int fd) {
// 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 @@ struct symtab* build_symtab(int fd) {
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 @@ void destroy_symtab(struct symtab* symta
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;
-
- 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);
+ return 0;
+
+ 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 @@ const char* nearest_symbol(struct symtab
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;
}