/** @brief Shows a backtrace of the current location */
XBT_PUBLIC(void) xbt_backtrace_display_current(void);
+/** @brief reimplementation of glibc backtrace based directly on gcc library, without implicit malloc */
+XBT_PUBLIC(int)xbt_backtrace_no_malloc(void**bt, int size);
/** @brief Captures a backtrace for further use */
XBT_PUBLIC(void) xbt_backtrace_current(xbt_ex_t * e);
/** @brief Display a previously captured backtrace */
int mmalloc_compare_heap(xbt_mheap_t mdp1, xbt_mheap_t mdp2, void *std_heap_addr);
+void mmalloc_backtrace_display(xbt_mheap_t mdp, void *addr);
+
#endif /* MMALLOC_H */
{
}
+#include <unwind.h>
+struct trace_arg {
+ void **array;
+ int cnt, size;
+};
+
+static _Unwind_Reason_Code
+backtrace_helper (struct _Unwind_Context *ctx, void *a)
+{
+ struct trace_arg *arg = a;
+
+ /* We are first called with address in the __backtrace function.
+ Skip it. */
+ if (arg->cnt != -1)
+ {
+ arg->array[arg->cnt] = (void *) _Unwind_GetIP(ctx);
+
+ /* Check whether we make any progress. */
+ if (arg->cnt > 0 && arg->array[arg->cnt - 1] == arg->array[arg->cnt])
+ return _URC_END_OF_STACK;
+ }
+ if (++arg->cnt == arg->size)
+ return _URC_END_OF_STACK;
+ return _URC_NO_REASON;
+}
+
+/** @brief reimplementation of glibc backtrace based directly on gcc library, without implicit malloc
+ *
+ * See http://webloria.loria.fr/~quinson/blog/2012/0208/system_programming_fun_in_SimGrid/
+ * for the motivation behind this function
+ * */
+
+int xbt_backtrace_no_malloc(void **array, int size) {
+ struct trace_arg arg = { .array = array, .size = size, .cnt = -1 };
+
+ if (size >= 1)
+ _Unwind_Backtrace(backtrace_helper, &arg);
+
+ /* _Unwind_Backtrace on IA-64 seems to put NULL address above
+ _start. Fix it up here. */
+ if (arg.cnt > 1 && arg.array[arg.cnt - 1] == NULL)
+ --arg.cnt;
+ return arg.cnt != -1 ? arg.cnt : 0;
+}
+
void xbt_backtrace_current(xbt_ex_t * e)
{
e->used = backtrace((void **) e->bt, XBT_BACKTRACE_SIZE);
}
-void xbt_ex_setup_backtrace(xbt_ex_t * e)
+void xbt_ex_setup_backtrace(xbt_ex_t * e) //FIXME: This code could be greatly improved/simplifyied with http://cairo.sourcearchive.com/documentation/1.9.4/backtrace-symbols_8c-source.html
{
int i;
&& e->used,
"Backtrace not setup yet, cannot set it up for display");
+ e->bt_strings = NULL;
+
if (!xbt_binary_name) /* no binary name, nothing to do */
return;
e->used--;
memmove(backtrace_syms, backtrace_syms + 1, sizeof(char *) * e->used);
- e->bt_strings = NULL;
/* Some arches only have stubs of backtrace, no implementation (hppa comes to mind) */
if (!e->used)
/* This program is free software; you can redistribute it and/or modify it
* under the terms of the license (GNU LGPL) which comes with this package. */
+#include "xbt/ex_interface.h" /* internals of backtrace setup */
+
+extern char *xbt_binary_name;
+
+void mmalloc_backtrace_display(xbt_mheap_t mdp, void *ptr){
+ size_t block = BLOCK(ptr);
+ int type;
+ xbt_ex_t e;
+
+ if ((char *) ptr < (char *) mdp->heapbase || block > mdp->heapsize) {
+ fprintf(stderr,"Ouch, this pointer is not mine. I cannot display its backtrace. I refuse it to death!!\n");
+ abort();
+ }
+
+ type = mdp->heapinfo[block].type;
+
+ if (type != 0) {
+ //fprintf(stderr,"Only full blocks are backtraced for now. Ignoring your request.\n");
+ return;
+ }
+ if (mdp->heapinfo[block].busy_block.bt_size == 0) {
+ fprintf(stderr,"No backtrace available for that block, sorry.\n");
+ return;
+ }
+
+ memcpy(&e.bt,&(mdp->heapinfo[block].busy_block.bt),sizeof(void*)*XBT_BACKTRACE_SIZE);
+ e.used = mdp->heapinfo[block].busy_block.bt_size;
+
+ xbt_ex_setup_backtrace(&e);
+ if (e.used == 0) {
+ fprintf(stderr, "(backtrace not set)\n");
+ } else if (e.bt_strings == NULL) {
+ fprintf(stderr, "(backtrace not ready to be computed. %s)\n",xbt_binary_name?"Dunno why":"xbt_binary_name not setup yet");
+ } else {
+ int i;
+
+ fprintf(stderr, "Backtrace of where the block %p where malloced (%d frames):\n",ptr,e.used);
+ for (i = 0; i < e.used; i++) /* no need to display "xbt_backtrace_display" */{
+ fprintf(stderr,"%d",i);fflush(NULL);
+ fprintf(stderr, "---> %s\n", e.bt_strings[i] + 4);
+ }
+ }
+}
int mmalloc_compare_heap(xbt_mheap_t mdp1, xbt_mheap_t mdp2, void *std_heap_addr){
newinfo[BLOCK(oldinfo)].busy_block.size = BLOCKIFY(mdp->heapsize * sizeof(malloc_info));
newinfo[BLOCK(oldinfo)].busy_block.busy_size = size;
+ newinfo[BLOCK(oldinfo)].busy_block.bt_size = 0;// FIXME setup the backtrace
mfree(mdp, (void *) oldinfo);
mdp->heapsize = newsize;
}
mdp->heapinfo[block+it].type = 0;
mdp->heapinfo[block].busy_block.size = blocks;
mdp->heapinfo[block].busy_block.busy_size = requested_size;
- // FIXME: setup backtrace
+ mdp->heapinfo[block].busy_block.bt_size=xbt_backtrace_no_malloc(mdp->heapinfo[block].busy_block.bt,XBT_BACKTRACE_SIZE);
return result;
}
mdp->heapinfo[block+it].type = 0;
mdp->heapinfo[block].busy_block.size = blocks;
mdp->heapinfo[block].busy_block.busy_size = requested_size;
+ mdp->heapinfo[block].busy_block.bt_size = 0;
}
//printf("(%s) Done mallocing. Result is %p\n",xbt_thread_self_name(),result);fflush(stdout);
return (result);
#define MMALLOC_MAGIC "mmalloc" /* Mapped file magic number */
#define MMALLOC_MAGIC_SIZE 8 /* Size of magic number buf */
-#define MMALLOC_VERSION 1 /* Current mmalloc version */
+#define MMALLOC_VERSION 2 /* Current mmalloc version */
/* The allocator divides the heap into blocks of fixed size; large
requests receive one or more whole blocks, and small requests
#define ADDRESS(B) ((void*) (((ADDR2UINT(B)) - 1) * BLOCKSIZE + (char*) mdp -> heapbase))
-const char *xbt_thread_self_name(void);
-
/* Doubly linked lists of free fragments. */
struct list {
struct list *next;
/* Data structure giving per-block information.
*
- * There is one such structure in the mdp->heapinfo array,
- * that is addressed by block number.
+ * There is one such structure in the mdp->heapinfo array per block used in that heap,
+ * the array index is the block number.
*
* There is several types of blocks in memory:
* - full busy blocks: used when we are asked to malloc a block which size is > BLOCKSIZE/2
* You can crawl the array and rely on that value.
*
* TODO:
- * - add an indication of the requested size in each fragment, similarly to busy_block.busy_size
* - make room to store the backtrace of where the blocks and fragment were malloced, too.
*/
typedef struct {
size_t nfree; /* Free fragments in a fragmented block. */
size_t first; /* First free fragment of the block. */
unsigned short frag_size[MAX_FRAGMENT_PER_BLOCK];
+ //void *bt[XBT_BACKTRACE_SIZE][MAX_FRAGMENT_PER_BLOCK]; /* Where it was malloced (or realloced lastly) */
} busy_frag;
struct {
size_t size; /* Size (in blocks) of a large cluster. */
size_t busy_size; /* Actually used space, in bytes */
+ void *bt[XBT_BACKTRACE_SIZE]; /* Where it was malloced (or realloced lastly) */
+ int bt_size;
} busy_block;
/* Heap information for a free block (that may be the first of a free cluster). */
struct {
/* Semaphore locking the access to the heap */
sem_t sem;
+ char locked;
/* Number of processes that attached the heap */
unsigned int refcount;
extern void *mmorecore(struct mdesc *mdp, int size);
/* Thread-safety (if the sem is already created) FIXME: KILLIT*/
-#define LOCK(mdp) \
- sem_wait(&mdp->sem)
-
-#define UNLOCK(mdp) \
- sem_post(&mdp->sem)
+#define LOCK(mdp) do { \
+ if (mdp->locked) \
+ fprintf(stderr,"panic! I'm not reintrant\n"); \
+ sem_wait(&mdp->sem); \
+ mdp->locked=1; \
+ } while(0)
+
+
+#define UNLOCK(mdp) do { \
+ sem_post(&mdp->sem); \
+ mdp->locked=0; \
+ } while (0)
#endif /* __MMPRIVATE_H */