forked from ianlancetaylor/cgosymbolizer
-
Notifications
You must be signed in to change notification settings - Fork 1
/
symbolizer.cc
126 lines (107 loc) · 3.3 KB
/
symbolizer.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "config.h"
#include <stdint.h>
#include <string.h>
#include <sys/types.h>
#include <stdlib.h>
#include <cxxabi.h>
extern "C" {
#include "backtrace.h"
#include "internal.h"
static void createStateErrorCallback(void* data, const char* msg, int errnum) {
}
static struct backtrace_state *cgoBacktraceState;
// Initialize the backtrace state.
void cgoSymbolizerInit(char* filename) {
cgoBacktraceState = backtrace_create_state(filename, 1, createStateErrorCallback, NULL);
}
struct cgoSymbolizerArg {
uintptr_t pc;
const char* file;
uintptr_t lineno;
const char* func;
uintptr_t entry;
uintptr_t more;
uintptr_t data;
};
struct cgoSymbolizerMore {
struct cgoSymbolizerMore *more;
const char* file;
uintptr_t lineno;
const char* func;
};
// Called via backtrace_pcinfo.
static int callback(void* data, uintptr_t pc, const char* filename, int lineno, const char* function) {
struct cgoSymbolizerArg* arg = (struct cgoSymbolizerArg*)(data);
struct cgoSymbolizerMore* more;
struct cgoSymbolizerMore** pp;
if (arg->file == NULL) {
arg->file = filename;
arg->lineno = lineno;
arg->func = function;
return 0;
}
more = (cgoSymbolizerMore*)backtrace_alloc(cgoBacktraceState, sizeof(*more), NULL, NULL);
if (more == NULL) {
return 1;
}
more->more = NULL;
more->file = filename;
more->lineno = lineno;
more->func = function;
for (pp = (struct cgoSymbolizerMore**)(&arg->data); *pp != NULL; pp = &(*pp)->more) {
}
*pp = more;
arg->more = 1;
return 0;
}
// Called via backtrace_pcinfo.
// Just ignore errors and let the caller indicate missing information.
static void errorCallback(void* data, const char* msg, int errnum) {
}
// Called via backtrace_syminfo.
// Just set the entry field.
static void syminfoCallback(void* data, uintptr_t pc, const char* symname, uintptr_t symval, uintptr_t symsize) {
struct cgoSymbolizerArg* arg = (struct cgoSymbolizerArg*)(data);
arg->entry = symval;
int status;
arg->func = abi::__cxa_demangle(symname, NULL, NULL, &status);
if (arg->func == NULL) {
arg->func = (const char *)malloc(strlen(symname)+1);
strcpy((char*)arg->func, symname);
}
}
// For the details of how this is called see runtime.SetCgoTraceback.
void cgoSymbolizer(void* parg) {
struct cgoSymbolizerArg* arg = (struct cgoSymbolizerArg*)(parg);
if (arg->data != 0) {
struct cgoSymbolizerMore* more = (struct cgoSymbolizerMore*)(arg->data);
arg->file = more->file;
arg->lineno = more->lineno;
arg->func = more->func;
arg->more = more->more != NULL;
arg->data = (uintptr_t)(more->more);
// If returning the last file/line, we can set the
// entry point field.
if (!arg->more) {
backtrace_syminfo(cgoBacktraceState, arg->pc, syminfoCallback, errorCallback, (void*)arg);
}
return;
}
free((void*)arg->func);
arg->file = NULL;
arg->lineno = 0;
arg->func = NULL;
arg->more = 0;
if (cgoBacktraceState == NULL || arg->pc == 0) {
return;
}
backtrace_pcinfo(cgoBacktraceState, arg->pc, callback, errorCallback, (void*)(arg));
// If returning only one file/line, we can set the entry point field.
if (!arg->more) {
backtrace_syminfo(cgoBacktraceState, arg->pc, syminfoCallback, errorCallback, (void*)arg);
}
}
}