1 /* 2 ** 2019-01-21 3 ** 4 ** The author disclaims copyright to this source code. In place of 5 ** a legal notice, here is a blessing: 6 ** 7 ** May you do good and not evil. 8 ** May you find forgiveness for yourself and forgive others. 9 ** May you share freely, never taking more than you give. 10 ** 11 ************************************************************************* 12 ** 13 ** This file implements an extension that uses the SQLITE_CONFIG_MALLOC 14 ** mechanism to add a tracing layer on top of SQLite. If this extension 15 ** is registered prior to sqlite3_initialize(), it will cause all memory 16 ** allocation activities to be logged on standard output, or to some other 17 ** FILE specified by the initializer. 18 ** 19 ** This file needs to be compiled into the application that uses it. 20 ** 21 ** This extension is used to implement the --memtrace option of the 22 ** command-line shell. 23 */ 24 #include <assert.h> 25 #include <string.h> 26 #include <stdio.h> 27 28 /* The original memory allocation routines */ 29 static sqlite3_mem_methods memtraceBase; 30 static FILE *memtraceOut; 31 32 /* Methods that trace memory allocations */ 33 static void *memtraceMalloc(int n){ 34 if( memtraceOut ){ 35 fprintf(memtraceOut, "MEMTRACE: allocate %d bytes\n", 36 memtraceBase.xRoundup(n)); 37 } 38 return memtraceBase.xMalloc(n); 39 } 40 static void memtraceFree(void *p){ 41 if( p==0 ) return; 42 if( memtraceOut ){ 43 fprintf(memtraceOut, "MEMTRACE: free %d bytes\n", memtraceBase.xSize(p)); 44 } 45 memtraceBase.xFree(p); 46 } 47 static void *memtraceRealloc(void *p, int n){ 48 if( p==0 ) return memtraceMalloc(n); 49 if( n==0 ){ 50 memtraceFree(p); 51 return 0; 52 } 53 if( memtraceOut ){ 54 fprintf(memtraceOut, "MEMTRACE: resize %d -> %d bytes\n", 55 memtraceBase.xSize(p), memtraceBase.xRoundup(n)); 56 } 57 return memtraceBase.xRealloc(p, n); 58 } 59 static int memtraceSize(void *p){ 60 return memtraceBase.xSize(p); 61 } 62 static int memtraceRoundup(int n){ 63 return memtraceBase.xRoundup(n); 64 } 65 static int memtraceInit(void *p){ 66 return memtraceBase.xInit(p); 67 } 68 static void memtraceShutdown(void *p){ 69 memtraceBase.xShutdown(p); 70 } 71 72 /* The substitute memory allocator */ 73 static sqlite3_mem_methods ersaztMethods = { 74 memtraceMalloc, 75 memtraceFree, 76 memtraceRealloc, 77 memtraceSize, 78 memtraceRoundup, 79 memtraceInit, 80 memtraceShutdown, 81 0 82 }; 83 84 /* Begin tracing memory allocations to out. */ 85 int sqlite3MemTraceActivate(FILE *out){ 86 int rc = SQLITE_OK; 87 if( memtraceBase.xMalloc==0 ){ 88 rc = sqlite3_config(SQLITE_CONFIG_GETMALLOC, &memtraceBase); 89 if( rc==SQLITE_OK ){ 90 rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &ersaztMethods); 91 } 92 } 93 memtraceOut = out; 94 return rc; 95 } 96 97 /* Deactivate memory tracing */ 98 int sqlite3MemTraceDeactivate(void){ 99 int rc = SQLITE_OK; 100 if( memtraceBase.xMalloc!=0 ){ 101 rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &memtraceBase); 102 if( rc==SQLITE_OK ){ 103 memset(&memtraceBase, 0, sizeof(memtraceBase)); 104 } 105 } 106 memtraceOut = 0; 107 return rc; 108 } 109