⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 trace.c

📁 debug source code under unix platform.
💻 C
字号:
/* * mpatrol * A library for controlling and tracing dynamic memory allocations. * Copyright (C) 1997-2002 Graeme S. Roy <graeme.roy@analog.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307, USA. *//* * Memory allocation tracing.  If tracing is enabled then all memory * allocations and deallocations are written to a file in a compact * format for later processing by a tracing tool. */#include "trace.h"#include "diag.h"#include "utils.h"#include "version.h"#include <stdio.h>#include <string.h>#if MP_IDENT_SUPPORT#ident "$Id: trace.c,v 1.19 2002/01/08 20:13:59 graeme Exp $"#else /* MP_IDENT_SUPPORT */static MP_CONST MP_VOLATILE char *trace_id = "$Id: trace.c,v 1.19 2002/01/08 20:13:59 graeme Exp $";#endif /* MP_IDENT_SUPPORT *//* A name cache is used to record the most recently-used strings that have been * written to the tracing output file.  Such strings can be replaced with * indices into the name cache.  When the name cache is full, the cache entry * that was accessed least recently will be replaced by a new name. */typedef struct namecache{    listnode node;        /* list node */    char *name;           /* pointer to name */    unsigned char index;  /* cache index */}namecache;/* A rescache structure stores information about memory reservations on the * heap before the tracing output file has been opened. */typedef struct rescache{    void *block;   /* pointer to block of memory */    size_t size;   /* size of block of memory */    char internal; /* allocation is internal */}rescache;#ifdef __cplusplusextern "C"{#endif /* __cplusplus *//* The arrays of cache entries for the function and file name caches. */static namecache funcnames[MP_NAMECACHE_SIZE];static namecache filenames[MP_NAMECACHE_SIZE];/* The lists of used and free cache entries for the function and file name * caches. */static listhead usedfuncs, freefuncs;static listhead usedfiles, freefiles;/* The cache that stores information about memory reservations on the heap * before the tracing output file has been opened.  The cachecounter variable * keeps a count of the number of entries stored in the cache. */static rescache cache[MP_RESCACHE_SIZE];static size_t cachecounter;/* The file pointer to the tracing output file.  This should not really be * a file scope variable as it prevents this module from being re-entrant. * The traceready variable indicates when the tracing output file is ready * to be used. */static FILE *tracefile;static int traceready;/* Initialise the fields of a tracehead so that the mpatrol library * is ready to trace memory allocations. */MP_GLOBALvoid__mp_newtrace(tracehead *t, meminfo *m){    size_t i;    t->file = __mp_tracefile(m, NULL);    t->tracing = 0;    __mp_newlist(&usedfuncs);    __mp_newlist(&freefuncs);    __mp_newlist(&usedfiles);    __mp_newlist(&freefiles);    for (i = 0; i < MP_NAMECACHE_SIZE; i++)    {        __mp_addtail(&freefuncs, &funcnames[i].node);        __mp_addtail(&freefiles, &filenames[i].node);        funcnames[i].name = filenames[i].name = NULL;        funcnames[i].index = filenames[i].index = i + 1;    }    tracefile = NULL;    traceready = 0;}/* Change the tracing output file and optionally terminate the old file. */MP_GLOBALint__mp_changetrace(tracehead *t, char *f, int e){    size_t i;    int r;    char s;    r = 1;    s = t->tracing;    if (e == 1)        r = __mp_endtrace(t);    else if ((tracefile == NULL) || (tracefile == stderr) ||             (tracefile == stdout))    {        /* We don't want to close the stderr or stdout file streams so         * we just flush them instead.  If the tracing file hasn't been set,         * this will just flush all open output files.         */        if (fflush(tracefile))            r = 0;    }    else if (fclose(tracefile))        r = 0;    t->file = f;    t->tracing = s;    __mp_newlist(&usedfuncs);    __mp_newlist(&freefuncs);    __mp_newlist(&usedfiles);    __mp_newlist(&freefiles);    for (i = 0; i < MP_NAMECACHE_SIZE; i++)    {        __mp_addtail(&freefuncs, &funcnames[i].node);        __mp_addtail(&freefiles, &filenames[i].node);        funcnames[i].name = filenames[i].name = NULL;    }    tracefile = NULL;    traceready = 0;    return r;}/* Finish tracing and attempt to close the tracing output file. */MP_GLOBALint__mp_endtrace(tracehead *t){    char s[4];    size_t i;    int r;    r = 1;    traceready = 0;    if ((t->tracing) && (tracefile != NULL))    {        __mp_memcopy(s, (char *) MP_TRACEMAGIC, 4);        fwrite(s, sizeof(char), 4, tracefile);    }    if ((tracefile == NULL) || (tracefile == stderr) || (tracefile == stdout))    {        /* We don't want to close the stderr or stdout file streams so         * we just flush them instead.  If the tracing file hasn't been set,         * this will just flush all open output files.         */        if (fflush(tracefile))            r = 0;    }    else if (fclose(tracefile))        r = 0;    tracefile = NULL;    __mp_newlist(&usedfuncs);    __mp_newlist(&freefuncs);    __mp_newlist(&usedfiles);    __mp_newlist(&freefiles);    for (i = 0; i < MP_NAMECACHE_SIZE; i++)    {        __mp_addtail(&freefuncs, &funcnames[i].node);        __mp_addtail(&freefiles, &filenames[i].node);        funcnames[i].name = filenames[i].name = NULL;    }    t->file = NULL;    t->tracing = 0;    return r;}/* Check that there were no errors writing to the tracing output file. */staticintchecktracefile(tracehead *t){    if (ferror(tracefile))    {        __mp_error(ET_MAX, AT_MAX, NULL, 0, "%s: problem writing tracing "                   "file\n", t->file);        __mp_endtrace(t);        return 0;    }    return 1;}/* Attempt to open the tracing output file. */staticintopentracefile(tracehead *t){    char s[4];    void *b;    size_t i, l;    unsigned long v;    /* The tracing file name can also be named as stderr and stdout which     * will go to the standard error and standard output streams respectively.     */    if (t->file == NULL)        return 0;    else if (strcmp(t->file, "stderr") == 0)        tracefile = stderr;    else if (strcmp(t->file, "stdout") == 0)        tracefile = stdout;    else if ((tracefile = fopen(t->file, "wb")) == NULL)    {        __mp_error(ET_MAX, AT_MAX, NULL, 0, "%s: cannot open file\n", t->file);        t->file = NULL;        return 0;    }    i = 1;    v = MP_VERNUM;    __mp_memcopy(s, (char *) MP_TRACEMAGIC, 4);    fwrite(s, sizeof(char), 4, tracefile);    fwrite(&i, sizeof(size_t), 1, tracefile);    fwrite(&v, sizeof(unsigned long), 1, tracefile);    traceready = 1;    /* Write out all of the entries in the memory reservation cache.  This     * only needs to be done when the tracing output file is opened since all     * subsequent tracing events will be written out directly.     */    for (i = 0; i < cachecounter; i++)    {        if (cache[i].internal)            fputc('I', tracefile);        else            fputc('H', tracefile);        b = __mp_encodeuleb128((unsigned long) cache[i].block, &l);        fwrite(b, l, 1, tracefile);        b = __mp_encodeuleb128(cache[i].size, &l);        fwrite(b, l, 1, tracefile);    }    cachecounter = 0;    return checktracefile(t);}/* Record a heap memory reservation for tracing. */MP_GLOBALvoid__mp_traceheap(void *a, size_t l, int i){    void *b;    size_t s;    if (!traceready)    {        /* If the tracing output file has not yet been opened then it is         * likely that the mpatrol library is still being initialised, in         * which case it is unsafe to open the file due to the possibility         * of recursion.  As a precautionary measure, we store the current         * information in a cache that will be written out when the file is         * finally opened.  If the cache is full, simply discard the current         * information.         */        if (cachecounter < MP_RESCACHE_SIZE)        {            cache[cachecounter].block = a;            cache[cachecounter].size = l;            cache[cachecounter].internal = i;            cachecounter++;        }        return;    }    if (i != 0)        fputc('I', tracefile);    else        fputc('H', tracefile);    /* Some of the following values are written as LEB128 numbers.  This is so     * that the size of the tracing output file can be kept to a minimum.     */    b = __mp_encodeuleb128((unsigned long) a, &s);    fwrite(b, s, 1, tracefile);    b = __mp_encodeuleb128(l, &s);    fwrite(b, s, 1, tracefile);}/* Add a string to a specified name cache or return the index of an existing * string. */staticunsigned charaddname(listhead *u, listhead *f, char *s){    namecache *n;    /* First check to see if the name already exists in the cache.     */    for (n = (namecache *) u->head; n->node.next != NULL;         n = (namecache *) n->node.next)        if ((*n->name == *s) && (strcmp(n->name + 1, s + 1) == 0))        {            /* If the entry is not at the front of the cache then move it there.             */            if (n != (namecache *) u->head)            {                __mp_remove(u, &n->node);                __mp_addhead(u, &n->node);            }            return n->index;        }    /* If there are free entries in the cache then use the first one, otherwise     * use the least-recently-used entry.     */    if (f->size > 0)        n = (namecache *) __mp_remhead(f);    else        n = (namecache *) __mp_remtail(u);    __mp_addhead(u, &n->node);    n->name = s;    return (unsigned char) (n->index | 0x80);}/* Write out a function name to the tracing output file. */staticvoidwritefuncname(char *s){    unsigned char n;    if ((s != NULL) && (*s != '\0'))    {        n = addname(&usedfuncs, &freefuncs, s);        fputc(n, tracefile);        if (n & 0x80)        {            fputs(s, tracefile);            fputc('\0', tracefile);        }    }    else        fputc('\0', tracefile);}/* Write out a file name to the tracing output file. */staticvoidwritefilename(char *s){    unsigned char n;    if ((s != NULL) && (*s != '\0'))    {        n = addname(&usedfiles, &freefiles, s);        fputc(n, tracefile);        if (n & 0x80)        {            fputs(s, tracefile);            fputc('\0', tracefile);        }    }    else        fputc('\0', tracefile);}/* Record a memory allocation for tracing. */MP_GLOBALvoid__mp_tracealloc(tracehead *t, unsigned long n, void *a, size_t l,                unsigned long d, char *f, char *g, unsigned long u){    void *b;    size_t s;    if ((tracefile == NULL) && !opentracefile(t))        return;    fputc('A', tracefile);    /* Some of the following values are written as LEB128 numbers.  This is so     * that the size of the tracing output file can be kept to a minimum.     */    b = __mp_encodeuleb128(n, &s);    fwrite(b, s, 1, tracefile);    b = __mp_encodeuleb128((unsigned long) a, &s);    fwrite(b, s, 1, tracefile);    b = __mp_encodeuleb128(l, &s);    fwrite(b, s, 1, tracefile);    b = __mp_encodeuleb128(d, &s);    fwrite(b, s, 1, tracefile);    writefuncname(f);    writefilename(g);    b = __mp_encodeuleb128(u, &s);    fwrite(b, s, 1, tracefile);    checktracefile(t);}/* Record a memory reallocation for tracing. */MP_GLOBALvoid__mp_tracerealloc(tracehead *t, unsigned long n, void *a, size_t l,                  unsigned long d, char *f, char *g, unsigned long u){    void *b;    size_t s;    if ((tracefile == NULL) && !opentracefile(t))        return;    fputc('R', tracefile);    /* Some of the following values are written as LEB128 numbers.  This is so     * that the size of the tracing output file can be kept to a minimum.     */    b = __mp_encodeuleb128(n, &s);    fwrite(b, s, 1, tracefile);    b = __mp_encodeuleb128((unsigned long) a, &s);    fwrite(b, s, 1, tracefile);    b = __mp_encodeuleb128(l, &s);    fwrite(b, s, 1, tracefile);    b = __mp_encodeuleb128(d, &s);    fwrite(b, s, 1, tracefile);    writefuncname(f);    writefilename(g);    b = __mp_encodeuleb128(u, &s);    fwrite(b, s, 1, tracefile);    checktracefile(t);}/* Record a memory deallocation for tracing. */MP_GLOBALvoid__mp_tracefree(tracehead *t, unsigned long n, unsigned long d, char *f, char *g,               unsigned long u){    void *b;    size_t s;    if ((tracefile == NULL) && !opentracefile(t))        return;    fputc('F', tracefile);    /* Some of the following values are written as LEB128 numbers.  This is so     * that the size of the tracing output file can be kept to a minimum.     */    b = __mp_encodeuleb128(n, &s);    fwrite(b, s, 1, tracefile);    b = __mp_encodeuleb128(d, &s);    fwrite(b, s, 1, tracefile);    writefuncname(f);    writefilename(g);    b = __mp_encodeuleb128(u, &s);    fwrite(b, s, 1, tracefile);    checktracefile(t);}#ifdef __cplusplus}#endif /* __cplusplus */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -