osMemory.c 8.9 KB
Newer Older
wafwerar's avatar
wafwerar 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
 * Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
 *
 * This program is free software: you can use, redistribute, and/or modify
 * it under the terms of the GNU Affero General Public License, version 3
 * or later ("AGPL"), as published by the Free Software Foundation.
 *
 * This program 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.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#define ALLOW_FORBID_FUNC
wafwerar's avatar
wafwerar 已提交
17
#include <malloc.h>
wafwerar's avatar
wafwerar 已提交
18 19
#include "os.h"

wafwerar's avatar
wafwerar 已提交
20
#if defined(USE_TD_MEMORY) || defined(USE_ADDR2LINE)
wafwerar's avatar
wafwerar 已提交
21

L
Liu Jicong 已提交
22
#define TD_MEMORY_SYMBOL ('T' << 24 | 'A' << 16 | 'O' << 8 | 'S')
wafwerar's avatar
wafwerar 已提交
23

24
#define TD_MEMORY_STACK_TRACE_DEPTH 10
wafwerar's avatar
wafwerar 已提交
25

26 27
typedef struct TdMemoryInfo *TdMemoryInfoPtr;

H
Haojun Liao 已提交
28
typedef struct TdMemoryInfo {
wafwerar's avatar
wafwerar 已提交
29
  int32_t symbol;
H
Haojun Liao 已提交
30
  int32_t memorySize;
L
Liu Jicong 已提交
31
  void   *stackTrace[TD_MEMORY_STACK_TRACE_DEPTH];  // gdb: disassemble /m 0xXXX
32 33 34
  // TdMemoryInfoPtr pNext;
  // TdMemoryInfoPtr pPrev;
} TdMemoryInfo;
wafwerar's avatar
wafwerar 已提交
35

36
// static TdMemoryInfoPtr GlobalMemoryPtr = NULL;
wafwerar's avatar
wafwerar 已提交
37

wafwerar's avatar
wafwerar 已提交
38
#ifdef WINDOWS
L
Liu Jicong 已提交
39
#define tstrdup(str) _strdup(str)
wafwerar's avatar
wafwerar 已提交
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82

int32_t taosBackTrace(void **buffer, int32_t size) {
  int32_t frame = 0;
  return frame;
}

#ifdef USE_ADDR2LINE
#include <DbgHelp.h>
#pragma comment(lib, "dbghelp.lib")

void taosPrintBackTrace() {
	#define MAX_STACK_FRAMES 20
	
	void *pStack[MAX_STACK_FRAMES];
 
	HANDLE process = GetCurrentProcess();
	SymInitialize(process, NULL, TRUE);
	WORD frames = CaptureStackBackTrace(1, MAX_STACK_FRAMES, pStack, NULL);
 
  char buf_tmp[1024];
	for (WORD i = 0; i < frames; ++i) {
		DWORD64 address = (DWORD64)(pStack[i]);
 
		DWORD64 displacementSym = 0;
		char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
		PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
		pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
		pSymbol->MaxNameLen = MAX_SYM_NAME;
 
		DWORD displacementLine = 0;
		IMAGEHLP_LINE64 line;
		//SymSetOptions(SYMOPT_LOAD_LINES);
		line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
 
		if (SymFromAddr(process, address, &displacementSym, pSymbol) && SymGetLineFromAddr64(process, address, &displacementLine, &line)) {
      snprintf(buf_tmp,sizeof(buf_tmp),"BackTrace %08" PRId64 " %s:%d %s\n", taosGetSelfPthreadId(), line.FileName, line.LineNumber, pSymbol->Name);
		} else {
			snprintf(buf_tmp,sizeof(buf_tmp),"BackTrace error: %d\n",GetLastError());
		}
    write(1,buf_tmp,strlen(buf_tmp));
	}
}
#endif
wafwerar's avatar
wafwerar 已提交
83
#else
L
Liu Jicong 已提交
84
#define tstrdup(str) strdup(str)
wafwerar's avatar
wafwerar 已提交
85

L
Liu Jicong 已提交
86
#include <execinfo.h>
wafwerar's avatar
wafwerar 已提交
87

wafwerar's avatar
wafwerar 已提交
88
#define STACKCALL __attribute__((regparm(1), noinline))
89
void **STACKCALL taosGetEbp(void) {
wafwerar's avatar
wafwerar 已提交
90 91 92 93 94 95 96
  void **ebp = NULL;
  __asm__ __volatile__("mov %%rbp, %0;\n\t"
                       : "=m"(ebp)  /* output */
                       :            /* input */
                       : "memory"); /* not affect register */
  return (void **)(*ebp);
}
wafwerar's avatar
wafwerar 已提交
97

wafwerar's avatar
wafwerar 已提交
98 99
int32_t taosBackTrace(void **buffer, int32_t size) {
  int32_t frame = 0;
L
Liu Jicong 已提交
100 101 102
  void  **ebp;
  void  **ret = NULL;
  size_t  func_frame_distance = 0;
wafwerar's avatar
wafwerar 已提交
103
  if (buffer != NULL && size > 0) {
104
    ebp = taosGetEbp();
wafwerar's avatar
wafwerar 已提交
105
    func_frame_distance = (size_t)*ebp - (size_t)ebp;
wafwerar's avatar
wafwerar 已提交
106 107 108 109 110
    while (ebp && frame < size && (func_frame_distance < (1ULL << 24))  // assume function ebp more than 16M
           && (func_frame_distance > 0)) {
      ret = ebp + 1;
      buffer[frame++] = *ret;
      ebp = (void **)(*ebp);
wafwerar's avatar
wafwerar 已提交
111
      func_frame_distance = (size_t)*ebp - (size_t)ebp;
wafwerar's avatar
wafwerar 已提交
112 113 114 115
    }
  }
  return frame;
}
wafwerar's avatar
wafwerar 已提交
116

117 118 119 120 121
// char **taosBackTraceSymbols(int32_t *size) {
//   void  *buffer[20] = {NULL};
//   *size = taosBackTrace(buffer, 20);
//   return backtrace_symbols(buffer, *size);
// }
wafwerar's avatar
wafwerar 已提交
122

wafwerar's avatar
wafwerar 已提交
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
#ifdef USE_ADDR2LINE

#include "osThread.h"
#include "libdwarf.h"
#include "dwarf.h"

#define DW_PR_DUu "llu"

typedef struct lookup_table
{
    Dwarf_Line *table;
    Dwarf_Line_Context *ctxts;
    int cnt;
    Dwarf_Addr low;
    Dwarf_Addr high;
} lookup_tableT;

extern int create_lookup_table(Dwarf_Debug dbg, lookup_tableT *lookup_table);
extern void delete_lookup_table(lookup_tableT *lookup_table);

size_t addr = 0;
lookup_tableT lookup_table;
Dwarf_Debug tDbg;
static TdThreadOnce traceThreadInit = PTHREAD_ONCE_INIT;

void endTrace() {
wafwerar's avatar
wafwerar 已提交
149 150
  TdThreadOnce tmp = PTHREAD_ONCE_INIT;
  if (memcmp(&traceThreadInit, &tmp, sizeof(TdThreadOnce)) != 0) {
wafwerar's avatar
wafwerar 已提交
151 152
    delete_lookup_table(&lookup_table);
    dwarf_finish(tDbg);
wafwerar's avatar
wafwerar 已提交
153
  }
wafwerar's avatar
wafwerar 已提交
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
}
void startTrace() {
  int ret;
  Dwarf_Ptr errarg = 0;

  FILE *fp = fopen("/proc/self/maps", "r");
  fscanf(fp, "%lx-", &addr);
  fclose(fp);

  ret = dwarf_init_path("/proc/self/exe", NULL, 0, DW_GROUPNUMBER_ANY, NULL, errarg, &tDbg, NULL);
  if (ret == DW_DLV_NO_ENTRY) {
    printf("Unable to open file");
    return;
  }

  ret = create_lookup_table(tDbg, &lookup_table);
  if (ret != DW_DLV_OK) {
    printf("Unable to create lookup table");
    return;
  }
  atexit(endTrace);
}
static void print_line(Dwarf_Debug dbg, Dwarf_Line line, Dwarf_Addr pc) {
wafwerar's avatar
wafwerar 已提交
177 178
  char *linesrc = "??";
  Dwarf_Unsigned lineno = 0;
wafwerar's avatar
wafwerar 已提交
179

wafwerar's avatar
wafwerar 已提交
180 181 182 183
  if (line) {
    dwarf_linesrc(line, &linesrc, NULL);
    dwarf_lineno(line, &lineno, NULL);
  }
184
  printf("BackTrace %08" PRId64 " %s:%" DW_PR_DUu "\n", taosGetSelfPthreadId(), linesrc, lineno);
wafwerar's avatar
wafwerar 已提交
185
  if (line) dwarf_dealloc(dbg, linesrc, DW_DLA_STRING);
wafwerar's avatar
wafwerar 已提交
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
}
void taosPrintBackTrace() {
  int size = 20;
  void **buffer[20];
  Dwarf_Addr pc;
  int32_t frame = 0;
  void **ebp;
  void **ret = NULL;
  size_t func_frame_distance = 0;

  taosThreadOnce(&traceThreadInit, startTrace);

  if (buffer != NULL && size > 0) {
      ebp = taosGetEbp();
    func_frame_distance = (size_t)*ebp - (size_t)ebp;
    while (ebp && frame < size && (func_frame_distance < (1ULL << 24)) && (func_frame_distance > 0)) {
      ret = ebp + 1;
      buffer[frame++] = *ret;
      ebp = (void **)(*ebp);
      func_frame_distance = (size_t)*ebp - (size_t)ebp;
    }
    for (size_t i = 0; i < frame; i++) {
      pc = (size_t)buffer[i] - addr;
      if (pc > 0) {
        if (pc >= lookup_table.low && pc < lookup_table.high) {
          Dwarf_Line line = lookup_table.table[pc - lookup_table.low];
          if (line) print_line(tDbg, line, pc);
        }
      }
    }
  }
}
#endif
#endif
#endif

#ifndef USE_ADDR2LINE
void taosPrintBackTrace() { return; }
wafwerar's avatar
wafwerar 已提交
224 225
#endif

wafwerar's avatar
wafwerar 已提交
226
void *taosMemoryMalloc(int32_t size) {
wafwerar's avatar
wafwerar 已提交
227
#ifdef USE_TD_MEMORY
wafwerar's avatar
wafwerar 已提交
228
  void *tmp = malloc(size + sizeof(TdMemoryInfo));
wafwerar's avatar
wafwerar 已提交
229 230 231 232 233
  if (tmp == NULL) return NULL;

  TdMemoryInfoPtr pTdMemoryInfo = (TdMemoryInfoPtr)tmp;
  pTdMemoryInfo->memorySize = size;
  pTdMemoryInfo->symbol = TD_MEMORY_SYMBOL;
L
Liu Jicong 已提交
234
  taosBackTrace(pTdMemoryInfo->stackTrace, TD_MEMORY_STACK_TRACE_DEPTH);
wafwerar's avatar
wafwerar 已提交
235

L
Liu Jicong 已提交
236
  return (char *)tmp + sizeof(TdMemoryInfo);
wafwerar's avatar
wafwerar 已提交
237 238 239
#else
  return malloc(size);
#endif
wafwerar's avatar
wafwerar 已提交
240 241 242
}

void *taosMemoryCalloc(int32_t num, int32_t size) {
wafwerar's avatar
wafwerar 已提交
243
#ifdef USE_TD_MEMORY
wafwerar's avatar
wafwerar 已提交
244
  int32_t memorySize = num * size;
L
Liu Jicong 已提交
245
  char   *tmp = calloc(memorySize + sizeof(TdMemoryInfo), 1);
wafwerar's avatar
wafwerar 已提交
246 247 248 249 250
  if (tmp == NULL) return NULL;

  TdMemoryInfoPtr pTdMemoryInfo = (TdMemoryInfoPtr)tmp;
  pTdMemoryInfo->memorySize = memorySize;
  pTdMemoryInfo->symbol = TD_MEMORY_SYMBOL;
L
Liu Jicong 已提交
251
  taosBackTrace(pTdMemoryInfo->stackTrace, TD_MEMORY_STACK_TRACE_DEPTH);
wafwerar's avatar
wafwerar 已提交
252

L
Liu Jicong 已提交
253
  return (char *)tmp + sizeof(TdMemoryInfo);
wafwerar's avatar
wafwerar 已提交
254 255 256
#else
  return calloc(num, size);
#endif
wafwerar's avatar
wafwerar 已提交
257 258 259
}

void *taosMemoryRealloc(void *ptr, int32_t size) {
wafwerar's avatar
wafwerar 已提交
260
#ifdef USE_TD_MEMORY
wafwerar's avatar
wafwerar 已提交
261
  if (ptr == NULL) return taosMemoryMalloc(size);
L
Liu Jicong 已提交
262 263

  TdMemoryInfoPtr pTdMemoryInfo = (TdMemoryInfoPtr)((char *)ptr - sizeof(TdMemoryInfo));
wafwerar's avatar
wafwerar 已提交
264 265 266 267 268 269 270
  assert(pTdMemoryInfo->symbol == TD_MEMORY_SYMBOL);

  TdMemoryInfo tdMemoryInfo;
  memcpy(&tdMemoryInfo, pTdMemoryInfo, sizeof(TdMemoryInfo));

  void *tmp = realloc(pTdMemoryInfo, size + sizeof(TdMemoryInfo));
  if (tmp == NULL) return NULL;
L
Liu Jicong 已提交
271

wafwerar's avatar
wafwerar 已提交
272 273 274
  memcpy(tmp, &tdMemoryInfo, sizeof(TdMemoryInfo));
  ((TdMemoryInfoPtr)tmp)->memorySize = size;

L
Liu Jicong 已提交
275
  return (char *)tmp + sizeof(TdMemoryInfo);
wafwerar's avatar
wafwerar 已提交
276 277 278
#else
  return realloc(ptr, size);
#endif
wafwerar's avatar
wafwerar 已提交
279 280
}

281 282 283
void *taosMemoryStrDup(void *ptr) {
#ifdef USE_TD_MEMORY
  if (ptr == NULL) return NULL;
L
Liu Jicong 已提交
284 285

  TdMemoryInfoPtr pTdMemoryInfo = (TdMemoryInfoPtr)((char *)ptr - sizeof(TdMemoryInfo));
286 287 288 289
  assert(pTdMemoryInfo->symbol == TD_MEMORY_SYMBOL);

  void *tmp = tstrdup((const char *)pTdMemoryInfo);
  if (tmp == NULL) return NULL;
L
Liu Jicong 已提交
290

291
  memcpy(tmp, pTdMemoryInfo, sizeof(TdMemoryInfo));
L
Liu Jicong 已提交
292
  taosBackTrace(((TdMemoryInfoPtr)tmp)->stackTrace, TD_MEMORY_STACK_TRACE_DEPTH);
293

L
Liu Jicong 已提交
294
  return (char *)tmp + sizeof(TdMemoryInfo);
295 296 297 298 299
#else
  return tstrdup((const char *)ptr);
#endif
}

wafwerar's avatar
wafwerar 已提交
300
void taosMemoryFree(void *ptr) {
wafwerar's avatar
wafwerar 已提交
301
#ifdef USE_TD_MEMORY
L
Liu Jicong 已提交
302 303
  TdMemoryInfoPtr pTdMemoryInfo = (TdMemoryInfoPtr)((char *)ptr - sizeof(TdMemoryInfo));
  if (pTdMemoryInfo->symbol == TD_MEMORY_SYMBOL) {
wafwerar's avatar
wafwerar 已提交
304 305
    pTdMemoryInfo->memorySize = 0;
    // memset(pTdMemoryInfo, 0, sizeof(TdMemoryInfo));
wafwerar's avatar
wafwerar 已提交
306 307
    free(pTdMemoryInfo);
  } else {
wafwerar's avatar
wafwerar 已提交
308
    free(ptr);
wafwerar's avatar
wafwerar 已提交
309
  }
wafwerar's avatar
wafwerar 已提交
310
#else
wafwerar's avatar
wafwerar 已提交
311
  return free(ptr);
wafwerar's avatar
wafwerar 已提交
312
#endif
wafwerar's avatar
wafwerar 已提交
313 314 315 316
}

int32_t taosMemorySize(void *ptr) {
  if (ptr == NULL) return 0;
wafwerar's avatar
wafwerar 已提交
317 318

#ifdef USE_TD_MEMORY
L
Liu Jicong 已提交
319
  TdMemoryInfoPtr pTdMemoryInfo = (TdMemoryInfoPtr)((char *)ptr - sizeof(TdMemoryInfo));
wafwerar's avatar
wafwerar 已提交
320 321 322
  assert(pTdMemoryInfo->symbol == TD_MEMORY_SYMBOL);

  return pTdMemoryInfo->memorySize;
wafwerar's avatar
wafwerar 已提交
323 324 325
#else
#ifdef WINDOWS
  return _msize(ptr);
wafwerar's avatar
wafwerar 已提交
326 327 328
#else
  return malloc_usable_size(ptr);
#endif
wafwerar's avatar
wafwerar 已提交
329
#endif
L
Liu Jicong 已提交
330
}