cause the stack to be marked as executable in order for them to work.
All assembler files have also had a declaration added so that the
object they generate will be marked as not needing an executable stack.
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@2446
return v_init_esp;
}
+static int prmap(void *start, void *end, const char *perm, off_t off, int maj, int min, int ino) {
+ printf("mapping %10p-%10p %s %02x:%02x %d\n",
+ start, end, perm, maj, min, ino);
+ return 1;
+}
+
static void hoops(void)
{
int err;
esp = fix_auxv(ume_exec_esp, &info);
if (0) {
- int prmap(void *start, void *end, const char *perm, off_t off, int maj, int min, int ino) {
- printf("mapping %10p-%10p %s %02x:%02x %d\n",
- start, end, perm, maj, min, ino);
- return 1;
- }
printf("---------- launch stage 2 ----------\n");
printf("eip=%p esp=%p\n", (void *)info.init_eip, esp);
foreach_map(prmap);
}
}
+static char *fillgap_addr;
+static char *fillgap_end;
+
+static int fillgap(void *segstart, void *segend, const char *perm, off_t off,
+ int maj, int min, int ino) {
+ if ((char *)segstart >= fillgap_end)
+ return 0;
+
+ if ((char *)segstart > fillgap_addr)
+ mmap(fillgap_addr, (char *)segstart-fillgap_addr, PROT_NONE,
+ MAP_FIXED|MAP_PRIVATE, padfile, 0);
+ fillgap_addr = segend;
+
+ return 1;
+}
+
/* pad all the empty spaces in a range of address space to stop
interlopers */
void as_pad(void *start, void *end)
{
char buf[1024];
- char *addr;
-
- int fillgap(void *segstart, void *segend, const char *perm, off_t off,
- int maj, int min, int ino) {
- if (segstart >= end)
- return 0;
-
- if ((char *)segstart > addr)
- mmap(addr, (char *)segstart-addr, PROT_NONE, MAP_FIXED|MAP_PRIVATE,
- padfile, 0);
- addr = segend;
-
- return 1;
- }
if (padfile == -1) {
int seq = 1;
fstat(padfile, &padstat);
}
- addr = start;
+ fillgap_addr = start;
+ fillgap_end = end;
foreach_map(fillgap);
- if (addr < (char *)end)
- mmap(addr, (char *)end-addr, PROT_NONE, MAP_FIXED|MAP_PRIVATE,
- padfile, 0);
+ if (fillgap_addr < fillgap_end)
+ mmap(fillgap_addr, fillgap_end-fillgap_addr, PROT_NONE,
+ MAP_FIXED|MAP_PRIVATE, padfile, 0);
}
-/* remove padding from a range of address space - padding is always a
- mapping of padfile*/
-void as_unpad(void *start, void *end)
-{
- int killpad(void *segstart, void *segend, const char *perm, off_t off,
- int maj, int min, int ino) {
- void *b, *e;
-
- if (padstat.st_dev != makedev(maj, min) || padstat.st_ino != ino)
- return 1;
-
- if (segend <= start || segstart >= end)
- return 1;
+static void *killpad_start;
+static void *killpad_end;
- if (segstart <= start)
- b = start;
- else
- b = segstart;
-
- if (segend >= end)
- e = end;
- else
- e = segend;
-
- munmap(b, (char *)e-(char *)b);
+static int killpad(void *segstart, void *segend, const char *perm, off_t off,
+ int maj, int min, int ino) {
+ void *b, *e;
+ if (padstat.st_dev != makedev(maj, min) || padstat.st_ino != ino)
return 1;
- }
+
+ if (segend <= killpad_start || segstart >= killpad_end)
+ return 1;
+
+ if (segstart <= killpad_start)
+ b = killpad_start;
+ else
+ b = segstart;
+
+ if (segend >= killpad_end)
+ e = killpad_end;
+ else
+ e = segend;
+
+ munmap(b, (char *)e-(char *)b);
+
+ return 1;
+}
+/* remove padding from a range of address space - padding is always a
+ mapping of padfile*/
+void as_unpad(void *start, void *end)
+{
if (padfile == -1) /* no padfile, no padding */
return;
-
+
+ killpad_start = start;
+ killpad_end = end;
+
foreach_map(killpad);
}
movl %ebp, %esp
popl %ebp
ret
+
+/* Let the linker know we don't need an executable stack */
+.section .note.GNU-stack,"",@progbits
+
+##--------------------------------------------------------------------##
+##--- end vg_cpuid.S ---##
+##--------------------------------------------------------------------##
.ascii "vg_dispatch: %ebp has invalid value!"
.byte 0
.text
-
+
+/* Let the linker know we don't need an executable stack */
+.section .note.GNU-stack,"",@progbits
##--------------------------------------------------------------------##
##--- end vg_dispatch.S ---##
}
/* Return the first VgHashNode satisfying the predicate p. */
-VgHashNode* VG_(HT_first_match) ( VgHashTable table, Bool (*p) ( VgHashNode* ))
+VgHashNode* VG_(HT_first_match) ( VgHashTable table,
+ Bool (*p) ( VgHashNode*, void* ),
+ void* d )
{
UInt i;
VgHashNode* node;
for (i = 0; i < VG_N_CHAINS; i++)
for (node = table[i]; node != NULL; node = node->next)
- if ( p(node) )
+ if ( p(node, d) )
return node;
return NULL;
}
-void VG_(HT_apply_to_all_nodes)( VgHashTable table, void (*f)(VgHashNode*) )
+void VG_(HT_apply_to_all_nodes)( VgHashTable table,
+ void (*f)(VgHashNode*, void*),
+ void* d )
{
UInt i;
VgHashNode* node;
for (i = 0; i < VG_N_CHAINS; i++) {
for (node = table[i]; node != NULL; node = node->next) {
- f(node);
+ f(node, d);
}
}
}
VG_(helper_undefined_instruction):
1: ud2
jmp 1b
-
+
+/* Let the linker know we don't need an executable stack */
+.section .note.GNU-stack,"",@progbits
+
##--------------------------------------------------------------------##
##--- end vg_helpers.S ---##
##--------------------------------------------------------------------##
/* Scan a colon-separated list, and call a function on each element.
The string must be mutable, because we insert a temporary '\0', but
- the string will end up unmodified. (*func) should return 1 if it
+ the string will end up unmodified. (*func) should return True if it
doesn't need to see any more.
+
+ This routine will return True if (*func) returns True and False if
+ it reaches the end of the list without that happening.
*/
-static void scan_colsep(char *colsep, int (*func)(const char *))
+static Bool scan_colsep(char *colsep, Bool (*func)(const char *))
{
char *cp, *entry;
int end;
if (colsep == NULL ||
*colsep == '\0')
- return;
+ return False;
entry = cp = colsep;
*cp = '\0';
if ((*func)(entry))
- end = 1;
+ return True;
*cp = save;
entry = cp+1;
}
cp++;
} while(!end);
+
+ return False;
+}
+
+static Bool contains(const char *p) {
+ if (VG_STREQ(p, VG_(libdir))) {
+ return True;
+ }
+ return False;
}
/* Prepare the client's environment. This is basically a copy of our
/* Walk over the new environment, mashing as we go */
for (cpp = ret; cpp && *cpp; cpp++) {
if (memcmp(*cpp, ld_library_path, ld_library_path_len) == 0) {
- int done = 0;
- int contains(const char *p) {
- if (VG_STREQ(p, VG_(libdir))) {
- done = 1;
- return 1;
- }
- return 0;
- }
-
/* If the LD_LIBRARY_PATH already contains libdir, then don't
bother adding it again, even if it isn't the first (it
seems that the Java runtime will keep reexecing itself
unless its paths are at the front of LD_LIBRARY_PATH) */
- scan_colsep(*cpp + ld_library_path_len, contains);
-
- if (!done) {
+ if (!scan_colsep(*cpp + ld_library_path_len, contains)) {
int len = strlen(*cpp) + vgliblen*2 + 16;
char *cp = malloc(len);
/*=== Find executable ===*/
/*====================================================================*/
+static const char* executable_name;
+
+static Bool match_executable(const char *entry) {
+ char buf[strlen(entry) + strlen(executable_name) + 2];
+
+ /* empty PATH element means . */
+ if (*entry == '\0')
+ entry = ".";
+
+ snprintf(buf, sizeof(buf), "%s/%s", entry, executable_name);
+
+ if (access(buf, R_OK|X_OK) == 0) {
+ executable_name = strdup(buf);
+ vg_assert(NULL != executable_name);
+ return True;
+ }
+ return False;
+}
+
static const char* find_executable(const char* exec)
{
vg_assert(NULL != exec);
- if (strchr(exec, '/') == NULL) {
+ executable_name = exec;
+ if (strchr(executable_name, '/') == NULL) {
/* no '/' - we need to search the path */
char *path = getenv("PATH");
- int pathlen = path ? strlen(path) : 0;
-
- int match_exe(const char *entry) {
- char buf[pathlen + strlen(entry) + 3];
-
- /* empty PATH element means . */
- if (*entry == '\0')
- entry = ".";
-
- snprintf(buf, sizeof(buf), "%s/%s", entry, exec);
-
- if (access(buf, R_OK|X_OK) == 0) {
- exec = strdup(buf);
- vg_assert(NULL != exec);
- return 1;
- }
- return 0;
- }
- scan_colsep(path, match_exe);
+ scan_colsep(path, match_executable);
}
- return exec;
+ return executable_name;
}
/*=== main() ===*/
/*====================================================================*/
+static int prmap(void *start, void *end, const char *perm, off_t off,
+ int maj, int min, int ino) {
+ printf("mapping %10p-%10p %s %02x:%02x %d\n",
+ start, end, perm, maj, min, ino);
+ return True;
+}
+
int main(int argc, char **argv)
{
char **cl_argv;
scan_auxv();
if (0) {
- int prmap(void *start, void *end, const char *perm, off_t off,
- int maj, int min, int ino) {
- printf("mapping %10p-%10p %s %02x:%02x %d\n",
- start, end, perm, maj, min, ino);
- return True;
- }
printf("========== main() ==========\n");
foreach_map(prmap);
}
return ret;
}
-
/* A general replacement for sprintf(). */
+
+static Char *vg_sprintf_ptr;
+
+static void add_to_vg_sprintf_buf ( Char c )
+{
+ *vg_sprintf_ptr++ = c;
+}
+
UInt VG_(sprintf) ( Char* buf, Char *format, ... )
{
Int ret;
va_list vargs;
- Char *ptr = buf;
- static void add_to_vg_sprintf_buf ( Char c )
- {
- *ptr++ = c;
- }
-
+
+ vg_sprintf_ptr = buf;
+
va_start(vargs,format);
ret = VG_(vprintf) ( add_to_vg_sprintf_buf, format, vargs );
VG_(baseBlock)-resident thread.
*/
ThreadId VG_(first_matching_thread_stack)
- ( Bool (*p) ( Addr stack_min, Addr stack_max ))
+ ( Bool (*p) ( Addr stack_min, Addr stack_max, void* d ),
+ void* d )
{
ThreadId tid, tid_to_skip;
if (vg_tid_currently_in_baseBlock != VG_INVALID_THREADID) {
tid = vg_tid_currently_in_baseBlock;
if ( p ( VG_(baseBlock)[VGOFF_(m_esp)],
- VG_(threads)[tid].stack_highest_word) )
+ VG_(threads)[tid].stack_highest_word, d ) )
return tid;
else
tid_to_skip = tid;
if (VG_(threads)[tid].status == VgTs_Empty) continue;
if (tid == tid_to_skip) continue;
if ( p ( VG_(threads)[tid].m_esp,
- VG_(threads)[tid].stack_highest_word) )
+ VG_(threads)[tid].stack_highest_word, d ) )
return tid;
}
return VG_INVALID_THREADID;
return ty->kind == TyPointer || is_composite(ty);
}
+/* Result buffer */
+static Char *describe_addr_buf;
+static UInt describe_addr_bufidx;
+static UInt describe_addr_bufsz;
+
+/* Add a character to the result buffer */
+static void describe_addr_addbuf(Char c) {
+ if ((describe_addr_bufidx+1) >= describe_addr_bufsz) {
+ Char *n;
+
+ if (describe_addr_bufsz == 0)
+ describe_addr_bufsz = 8;
+ else
+ describe_addr_bufsz *= 2;
+
+ /* use tool malloc so that the skin client can free it */
+ n = VG_(malloc)(describe_addr_bufsz);
+ if (describe_addr_buf != NULL && describe_addr_bufidx != 0)
+ VG_(memcpy)(n, describe_addr_buf, describe_addr_bufidx);
+ if (describe_addr_buf != NULL)
+ VG_(free)(describe_addr_buf);
+ describe_addr_buf = n;
+ }
+ describe_addr_buf[describe_addr_bufidx++] = c;
+ describe_addr_buf[describe_addr_bufidx] = '\0';
+}
+
#define MAX_PLY 7 /* max depth we go */
#define MAX_ELEMENTS 5000 /* max number of array elements we scan */
#define MAX_VARS 10000 /* max number of variables total traversed */
Variable *list; /* worklist */
Variable *keeplist; /* container variables */
Variable *found; /* the chain we found */
- Char *buf = NULL; /* the result */
- UInt bufsz = 0;
- UInt bufidx = 0;
Int created=0, freed=0;
Int numvars = MAX_VARS;
- /* add a character to the result buffer */
- void addbuf(Char c) {
- if ((bufidx+1) >= bufsz) {
- Char *n;
-
- if (bufsz == 0)
- bufsz = 8;
- else
- bufsz *= 2;
-
- /* use tool malloc so that the skin client can free it */
- n = VG_(malloc)(bufsz);
- if (buf != NULL && bufidx != 0)
- VG_(memcpy)(n, buf, bufidx);
- if (buf != NULL)
- VG_(free)(buf);
- buf = n;
- }
- buf[bufidx++] = c;
- buf[bufidx] = '\0';
- }
-
+ describe_addr_buf = NULL;
+ describe_addr_bufidx = 0;
+ describe_addr_bufsz = 0;
clear_visited();
found->container->name = NULL;
found->container = found->container->container;
} else {
- bprintf(addbuf, "&(");
+ bprintf(describe_addr_addbuf, "&(");
ptr = False;
}
*ep++ = '\0';
- bprintf(addbuf, sp);
+ bprintf(describe_addr_addbuf, sp);
if (addr != found->valuep)
- bprintf(addbuf, "+%d", addr - found->valuep);
+ bprintf(describe_addr_addbuf, "+%d", addr - found->valuep);
if (VG_(get_filename_linenum)(eip, file, sizeof(file), &line))
- bprintf(addbuf, " at %s:%d", file, line, addr);
+ bprintf(describe_addr_addbuf, " at %s:%d", file, line, addr);
}
}
clear_visited();
if (debug)
- VG_(printf)("returning buf=%s\n", buf);
+ VG_(printf)("returning buf=%s\n", describe_addr_buf);
- return buf;
+ return describe_addr_buf;
}
#endif /* TEST */
VG_(sigreturn):
movl $__NR_rt_sigreturn, %eax
int $0x80
-
+
+/* Let the linker know we don't need an executable stack */
+.section .note.GNU-stack,"",@progbits
+
##--------------------------------------------------------------------##
##--- end vg_syscall.S ---##
##--------------------------------------------------------------------##
}
/* Unchain any jumps pointing to a sector we're about to free */
+static Addr sector_base;
+static Addr sector_len;
+
+static
+void unchain_site_for_sector(Addr a) {
+ Addr jmp = VG_(get_jmp_dest)(a);
+ if (jmp >= sector_base && jmp < (sector_base+sector_len))
+ VG_(unchain_jumpsite)(a);
+}
+
+static
+void unchain_tce_for_sector(TCEntry *tce) {
+ for_each_jumpsite(tce, unchain_site_for_sector);
+}
+
static
void unchain_sector(Int s, Addr base, UInt len)
{
- void unchain_site(Addr a) {
- Addr jmp = VG_(get_jmp_dest)(a);
- if (jmp >= base && jmp < (base+len))
- VG_(unchain_jumpsite)(a);
- }
- void _unchain_tce(TCEntry *tce) {
- for_each_jumpsite(tce, unchain_site);
- }
+ sector_base = base;
+ sector_len = len;
- for_each_tc(s, _unchain_tce);
+ for_each_tc(s, unchain_tce_for_sector);
}
.data
.globl ume_exec_esp
ume_exec_esp: .long 0
+
+/* Let the linker know we don't need an executable stack */
+.section .note.GNU-stack,"",@progbits
#define MARK_LOOP (graph_mark+0)
#define MARK_DONE (graph_mark+1)
-static Bool check_cycle(const Mutex *start, const LockSet* lockset)
+static Bool check_cycle_inner(const Mutex *mutex, const LockSet *ls)
{
- Bool check_cycle_inner(const Mutex *mutex, const LockSet *ls)
- {
- static const Bool debug = False;
- Int i;
-
- if (mutex->mark == MARK_LOOP)
- return True; /* found cycle */
- if (mutex->mark == MARK_DONE)
- return False; /* been here before, its OK */
+ static const Bool debug = False;
+ Int i;
- ((Mutex*)mutex)->mark = MARK_LOOP;
-
+ if (mutex->mark == MARK_LOOP)
+ return True; /* found cycle */
+ if (mutex->mark == MARK_DONE)
+ return False; /* been here before, its OK */
+
+ ((Mutex*)mutex)->mark = MARK_LOOP;
+
+ if (debug)
+ VG_(printf)("mark=%d visiting %p%(y mutex->lockset=%d\n",
+ graph_mark, mutex->mutexp, mutex->mutexp, mutex->lockdep);
+ for(i = 0; i < ls->setsize; i++) {
+ const Mutex *mx = ls->mutex[i];
+
if (debug)
- VG_(printf)("mark=%d visiting %p%(y mutex->lockset=%d\n",
- graph_mark, mutex->mutexp, mutex->mutexp, mutex->lockdep);
- for(i = 0; i < ls->setsize; i++) {
- const Mutex *mx = ls->mutex[i];
-
- if (debug)
- VG_(printf)(" %y ls=%p (ls->mutex=%p%(y)\n",
- mutex->mutexp, ls,
- mx->mutexp, mx->mutexp);
- if (check_cycle_inner(mx, mx->lockdep))
- return True;
- }
- ((Mutex*)mutex)->mark = MARK_DONE;
-
- return False;
+ VG_(printf)(" %y ls=%p (ls->mutex=%p%(y)\n",
+ mutex->mutexp, ls,
+ mx->mutexp, mx->mutexp);
+ if (check_cycle_inner(mx, mx->lockdep))
+ return True;
}
+ ((Mutex*)mutex)->mark = MARK_DONE;
+
+ return False;
+}
+
+static Bool check_cycle(const Mutex *start, const LockSet* lockset)
+{
graph_mark += 2; /* clear all marks */
/*--- Setting and checking permissions. ---*/
/*------------------------------------------------------------*/
+/* only clean up dead mutexes */
+static
+Bool cleanmx(Mutex *mx) {
+ return mx->state == MxDead;
+}
+
static
void set_address_range_state ( Addr a, UInt len /* in bytes */,
VgeInitStatus status )
{
Addr end;
- /* only clean up dead mutexes */
- Bool cleanmx(Mutex *mx) {
- return mx->state == MxDead;
- }
-
-
# if DEBUG_MAKE_ACCESSES
VG_(printf)("make_access: 0x%x, %u, status=%u\n", a, len, status);
# endif
/*is_zeroed*/True );
}
+static ThreadId deadmx_tid;
+
+static
+Bool deadmx(Mutex *mx) {
+ if (mx->state != MxDead)
+ set_mutex_state(mx, MxDead, deadmx_tid);
+
+ return False;
+}
+
static
void die_and_free_mem ( ThreadId tid, HG_Chunk* hc,
HG_Chunk** prev_chunks_next_ptr )
Addr start = hc->data;
Addr end = start + hc->size;
- Bool deadmx(Mutex *mx) {
- if (mx->state != MxDead)
- set_mutex_state(mx, MxDead, tid);
-
- return False;
- }
-
/* Remove hc from the malloclist using prev_chunks_next_ptr to
avoid repeating the hash table lookup. Can't remove until at least
after free and free_mismatch errors are done because they use
freechunkptr = 0;
/* mark all mutexes in range dead */
+ deadmx_tid = tid;
find_mutex_range(start, end, deadmx);
}
/* Describe an address as best you can, for error messages,
putting the result in ai. */
+/* Callback for searching malloc'd and free'd lists */
+static Bool addr_is_in_block(VgHashNode *node, void *ap)
+{
+ HG_Chunk* hc2 = (HG_Chunk*)node;
+ Addr a = *(Addr *)ap;
+
+ return (hc2->data <= a && a < hc2->data + hc2->size);
+}
+
static void describe_addr ( Addr a, AddrInfo* ai )
{
HG_Chunk* hc;
Int i;
- /* Nested functions, yeah. Need the lexical scoping of 'a'. */
-
- /* Closure for searching thread stacks */
- Bool addr_is_in_bounds(Addr stack_min, Addr stack_max)
- {
- return (stack_min <= a && a <= stack_max);
- }
- /* Closure for searching malloc'd and free'd lists */
- Bool addr_is_in_block(VgHashNode *node)
- {
- HG_Chunk* hc2 = (HG_Chunk*)node;
- return (hc2->data <= a && a < hc2->data + hc2->size);
- }
-
/* Search for it in segments */
{
const SegInfo *seg;
}
/* Search for a currently malloc'd block which might bracket it. */
- hc = (HG_Chunk*)VG_(HT_first_match)(hg_malloc_list, addr_is_in_block);
+ hc = (HG_Chunk*)VG_(HT_first_match)(hg_malloc_list, addr_is_in_block, &a);
if (NULL != hc) {
ai->akind = Mallocd;
ai->blksize = hc->size;
/* Searches through all thread's stacks to see if any match. Returns
VG_INVALID_THREADID if none match. */
extern ThreadId VG_(first_matching_thread_stack)
- ( Bool (*p) ( Addr stack_min, Addr stack_max ));
+ ( Bool (*p) ( Addr stack_min, Addr stack_max, void* d ),
+ void* d );
/*====================================================================*/
extern VgHashNode** VG_(HT_to_array) ( VgHashTable t, /*OUT*/ UInt* n_shadows );
/* Returns first node that matches predicate `p', or NULL if none do.
- Extra arguments can be implicitly passed to `p' using nested functions;
- see memcheck/mc_errcontext.c for an example. */
+ Extra arguments can be implicitly passed to `p' using `d' which is an
+ opaque pointer passed to `p' each time it is called. */
extern VgHashNode* VG_(HT_first_match) ( VgHashTable t,
- Bool (*p)(VgHashNode*) );
-
-/* Applies a function f() once to each node. Again, nested functions
- can be very useful. */
-extern void VG_(HT_apply_to_all_nodes)( VgHashTable t, void (*f)(VgHashNode*) );
+ Bool (*p)(VgHashNode*, void*),
+ void* d );
+
+/* Applies a function f() once to each node. Again, `d' can be used
+ to pass extra information to the function. */
+extern void VG_(HT_apply_to_all_nodes)( VgHashTable t,
+ void (*f)(VgHashNode*, void*),
+ void* d );
/* Destroy a table. */
extern void VG_(HT_destruct) ( VgHashTable t );
static UInt curr_census = 0;
// Must return False so that all stacks are traversed
-static UInt count_stack_size_counter;
-static Bool count_stack_size( Addr stack_min, Addr stack_max )
+static Bool count_stack_size( Addr stack_min, Addr stack_max, void *cp )
{
- count_stack_size_counter += (stack_max - stack_min);
+ *(UInt *)cp += (stack_max - stack_min);
return False;
}
// Stack(s) ---------------------------------------------------------
if (clo_stacks) {
- count_stack_size_counter = sigstacks_space;
+ census->stacks_space = sigstacks_space;
// slightly abusing this function
- VG_(first_matching_thread_stack)( count_stack_size );
- census->stacks_space = count_stack_size_counter;
+ VG_(first_matching_thread_stack)( count_stack_size, &census->stacks_space );
i++;
}
}
/* Return the first shadow chunk satisfying the predicate p. */
-MAC_Chunk* MAC_(first_matching_freed_MAC_Chunk) ( Bool (*p)(MAC_Chunk*) )
+MAC_Chunk* MAC_(first_matching_freed_MAC_Chunk) ( Bool (*p)(MAC_Chunk*, void*),
+ void* d )
{
MAC_Chunk* mc;
/* No point looking through freed blocks if we're not keeping
them around for a while... */
for (mc = freed_list_start; mc != NULL; mc = mc->next)
- if (p(mc))
+ if (p(mc, d))
return mc;
return NULL;
}
+static void destroy_mempool_nuke_chunk(VgHashNode *node, void *d)
+{
+ MAC_Chunk *mc = (MAC_Chunk *)node;
+ MAC_Mempool *mp = (MAC_Mempool *)d;
+
+ /* Note: ban redzones again -- just in case user de-banned them
+ with a client request... */
+ MAC_(ban_mem_heap)(mc->data-mp->rzB, mp->rzB );
+ MAC_(die_mem_heap)(mc->data, mc->size );
+ MAC_(ban_mem_heap)(mc->data+mc->size, mp->rzB );
+}
+
void MAC_(destroy_mempool)(Addr pool)
{
- MAC_Mempool* mp;
+ MAC_Mempool* mp;
MAC_Mempool** prev_next;
- void nuke_chunk(VgHashNode *node)
- {
- MAC_Chunk *mc = (MAC_Chunk *)node;
-
- /* Note: ban redzones again -- just in case user de-banned them
- with a client request... */
- MAC_(ban_mem_heap)(mc->data-mp->rzB, mp->rzB );
- MAC_(die_mem_heap)(mc->data, mc->size );
- MAC_(ban_mem_heap)(mc->data+mc->size, mp->rzB );
- }
-
- mp = (MAC_Mempool*)VG_(HT_get_node) ( MAC_(mempool_list), (UInt)pool,
- (VgHashNode***)&prev_next );
+ mp = (MAC_Mempool*)VG_(HT_get_node) ( MAC_(mempool_list),
+ (UInt)pool,
+ (VgHashNode***)&prev_next );
if (mp == NULL) {
ThreadId tid = VG_(get_current_or_recent_tid)();
}
*prev_next = mp->next;
- VG_(HT_apply_to_all_nodes)(mp->chunks, nuke_chunk);
+ VG_(HT_apply_to_all_nodes)(mp->chunks, destroy_mempool_nuke_chunk, mp);
VG_(HT_destruct)(mp->chunks);
VG_(free)(mp);
die_and_free_mem(mc, prev_chunk, mp->rzB);
}
+typedef
+ struct {
+ UInt nblocks;
+ UInt nbytes;
+ }
+ MallocStats;
+
+static void malloc_stats_count_chunk(VgHashNode* node, void* d) {
+ MAC_Chunk* mc = (MAC_Chunk*)node;
+ MallocStats *ms = (MallocStats *)d;
+
+ ms->nblocks ++;
+ ms->nbytes += mc->size;
+}
+
void MAC_(print_malloc_stats) ( void )
{
- UInt nblocks = 0, nbytes = 0;
+ MallocStats ms;
+
+ ms.nblocks = 0;
+ ms.nbytes = 0;
/* Mmm... more lexical scoping */
- void count_one_chunk(VgHashNode* node) {
- MAC_Chunk* mc = (MAC_Chunk*)node;
- nblocks ++;
- nbytes += mc->size;
- }
-
if (VG_(clo_verbosity) == 0)
return;
/* Count memory still in use. */
- VG_(HT_apply_to_all_nodes)(MAC_(malloc_list), count_one_chunk);
+ VG_(HT_apply_to_all_nodes)(MAC_(malloc_list), malloc_stats_count_chunk, &ms);
VG_(message)(Vg_UserMsg,
"malloc/free: in use at exit: %d bytes in %d blocks.",
- nbytes, nblocks);
+ ms.nbytes, ms.nblocks);
VG_(message)(Vg_UserMsg,
"malloc/free: %d allocs, %d frees, %u bytes allocated.",
cmalloc_n_mallocs,
/* Additional description function for describe_addr(); used by
MemCheck for user blocks, which Addrcheck doesn't support. */
Bool (*MAC_(describe_addr_supp)) ( Addr a, AddrInfo* ai ) = NULL;
-
+
+/* Callback for searching thread stacks */
+static Bool addr_is_in_bounds(Addr stack_min, Addr stack_max, void *ap)
+{
+ Addr a = *(Addr *)ap;
+
+ return (stack_min <= a && a <= stack_max);
+}
+
+/* Callback for searching free'd list */
+static Bool addr_is_in_MAC_Chunk(MAC_Chunk* mc, void *ap)
+{
+ Addr a = *(Addr *)ap;
+
+ return VG_(addr_is_in_block)( a, mc->data, mc->size );
+}
+
+/* Callback for searching malloc'd lists */
+static Bool addr_is_in_HashNode(VgHashNode* sh_ch, void *ap)
+{
+ return addr_is_in_MAC_Chunk( (MAC_Chunk*)sh_ch, ap );
+}
+
/* Describe an address as best you can, for error messages,
putting the result in ai. */
static void describe_addr ( Addr a, AddrInfo* ai )
MAC_Chunk* sc;
ThreadId tid;
- /* Nested functions, yeah. Need the lexical scoping of 'a'. */
-
- /* Closure for searching thread stacks */
- Bool addr_is_in_bounds(Addr stack_min, Addr stack_max)
- {
- return (stack_min <= a && a <= stack_max);
- }
- /* Closure for searching free'd list */
- Bool addr_is_in_MAC_Chunk(MAC_Chunk* mc)
- {
- return VG_(addr_is_in_block)( a, mc->data, mc->size );
- }
- /* Closure for searching malloc'd lists */
- Bool addr_is_in_HashNode(VgHashNode* sh_ch)
- {
- return addr_is_in_MAC_Chunk( (MAC_Chunk*)sh_ch );
- }
-
/* Perhaps it's a user-def'd block ? (only check if requested, though) */
if (NULL != MAC_(describe_addr_supp)) {
if (MAC_(describe_addr_supp)( a, ai ))
return;
}
/* Perhaps it's on a thread's stack? */
- tid = VG_(first_matching_thread_stack)(addr_is_in_bounds);
+ tid = VG_(first_matching_thread_stack)(addr_is_in_bounds, &a);
if (tid != VG_INVALID_THREADID) {
ai->akind = Stack;
ai->stack_tid = tid;
return;
}
/* Search for a recently freed block which might bracket it. */
- sc = MAC_(first_matching_freed_MAC_Chunk)(addr_is_in_MAC_Chunk);
+ sc = MAC_(first_matching_freed_MAC_Chunk)(addr_is_in_MAC_Chunk, &a);
if (NULL != sc) {
ai->akind = Freed;
ai->blksize = sc->size;
return;
}
/* Search for a currently malloc'd block which might bracket it. */
- sc = (MAC_Chunk*)VG_(HT_first_match)(MAC_(malloc_list), addr_is_in_HashNode);
+ sc = (MAC_Chunk*)VG_(HT_first_match)(MAC_(malloc_list), addr_is_in_HashNode, &a);
if (NULL != sc) {
ai->akind = Mallocd;
ai->blksize = sc->size;
extern void MAC_(pp_shared_SkinError) ( Error* err);
-extern MAC_Chunk* MAC_(first_matching_freed_MAC_Chunk)( Bool (*p)(MAC_Chunk*) );
+extern MAC_Chunk* MAC_(first_matching_freed_MAC_Chunk)( Bool (*p)(MAC_Chunk*, void*), void* d );
extern void MAC_(common_pre_clo_init) ( void );
extern void MAC_(common_fini) ( void (*leak_check)(void) );
);
}
+static Bool find_addr(VgHashNode* sh_ch, void* ap)
+{
+ MAC_Chunk *m = (MAC_Chunk*)sh_ch;
+ Addr a = *(Addr*)ap;
+
+ return VG_(addr_is_in_block)(a, m->data, m->size);
+}
+
Bool MC_(client_perm_maybe_describe)( Addr a, AddrInfo* ai )
{
UInt i;
if(mp->chunks != NULL) {
MAC_Chunk *mc;
- Bool find_addr(VgHashNode* sh_ch)
- {
- MAC_Chunk *m = (MAC_Chunk*)sh_ch;
- return VG_(addr_is_in_block)(a, m->data, m->size);
- }
-
- mc = (MAC_Chunk*)VG_(HT_first_match)(mp->chunks, find_addr);
+ mc = (MAC_Chunk*)VG_(HT_first_match)(mp->chunks, find_addr, &a);
if(mc != NULL) {
ai->akind = UserG;
ai->blksize = mc->size;
call MC_(helperc_value_check4_fail)
popal
ret
+
+/* Let the linker know we don't need an executable stack */
+.section .note.GNU-stack,"",@progbits
##--------------------------------------------------------------------##
##--- end mc_helpers.S ---##
##--------------------------------------------------------------------##
-