-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlat_translator.c
199 lines (169 loc) · 3.92 KB
/
lat_translator.c
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
/*
* Copyright 2010-2013 Red Hat Inc.
* Author: Michal Schmidt
* License: GPLv2
*/
#include <sys/types.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "rbtree.h"
#include "sym_translator.h"
struct symbol_translation {
struct rb_node rb_node;
char *symbol;
char *translation;
int prio;
};
static struct rb_root sym2trans = RB_ROOT;
static struct symbol_translation *__insert_symbol(const char *symbol, struct symbol_translation *st)
{
struct rb_node **p = &sym2trans.rb_node;
struct rb_node *parent = NULL;
struct symbol_translation *ist;
int cmp;
while (*p) {
parent = *p;
ist = rb_entry(parent, struct symbol_translation, rb_node);
cmp = strcmp(symbol, ist->symbol);
if (cmp < 0)
p = &(*p)->rb_left;
else if (cmp > 0)
p = &(*p)->rb_right;
else
return ist;
}
rb_link_node(&st->rb_node, parent, p);
return NULL;
}
static struct symbol_translation *insert_symbol(const char *symbol, struct symbol_translation *st)
{
struct symbol_translation *ret;
if ((ret = __insert_symbol(symbol, st))) {
/* we already know this address. some alias? */
free(st->symbol);
free(st->translation);
free(st);
goto out;
}
rb_insert_color(&st->rb_node, &sym2trans);
out:
return ret;
}
static int parse_latencytop_trans(void)
{
FILE *f;
char *line = NULL;
size_t len = 0;
ssize_t read;
int prio;
char *symbol;
char *translation;
struct symbol_translation *st;
f = fopen("/usr/share/latencytop/latencytop.trans", "re");
if (!f) {
perror("/usr/share/latencytop/latencytop.trans");
return -errno;
}
while ((read = getline(&line, &len, f)) != -1) {
if (line[0] == '#' || line[0] == '\n')
continue;
if (sscanf(line, "%d %ms %m[^\n]", &prio, &symbol, &translation) != 3) {
fprintf(stderr, "Failed to parse line, ignoring: %s", line);
continue;
}
st = malloc(sizeof(struct symbol_translation));
st->symbol = symbol;
st->translation = translation;
st->prio = prio;
insert_symbol(symbol, st);
}
if (line)
free(line);
fclose(f);
return 0;
}
struct symbol_translation *lookup_symbol(const char *symbol)
{
struct rb_node *n = sym2trans.rb_node;
struct symbol_translation *st;
int cmp;
while (n) {
st = rb_entry(n, struct symbol_translation, rb_node);
cmp = strcmp(symbol, st->symbol);
if (cmp < 0)
n = n->rb_left;
else if (cmp > 0)
n = n->rb_right;
else
return st;
}
return NULL;
}
static void delete_symbols(struct rb_node *n)
{
struct symbol_translation *s;
if (!n)
return;
delete_symbols(n->rb_left);
delete_symbols(n->rb_right);
s = rb_entry(n, struct symbol_translation, rb_node);
free(s->symbol);
free(s->translation);
free(s);
}
int lat_translator_lookup(const char *symbol, const char **translation, int *prio)
{
struct symbol_translation *st = lookup_symbol(symbol);
if (!st)
return -ENOENT;
*translation = st->translation;
*prio = st->prio;
return 0;
}
const char *lat_translator_translate_stack(char *symbolic_stack_trace)
{
const char *translation, *best_translation = NULL;
char *p;
size_t len;
int prio, best_prio = INT_MIN;
char tmp;
p = symbolic_stack_trace;
while (*p) {
/* skip spaces */
p += strspn(p, " ");
if (*p == '\0')
break;
/* isolate single symbol */
len = strcspn(p, " ");
tmp = p[len];
p[len] = '\0'; /* cut */
if (lat_translator_lookup(p, &translation, &prio) == 0 &&
prio > best_prio) {
best_prio = prio;
best_translation = translation;
}
p[len] = tmp; /* uncut */
p += len;
}
return best_translation ?: NULL;
}
/*void lat_translator_dump(void)
{
struct rb_node *node;
struct symbol_translation *st;
for (node = rb_first(&sym2trans); node; node = rb_next(node)) {
st = rb_entry(node, struct symbol_translation, rb_node);
printf("%d %s => %s\n", st->prio, st->symbol, st->translation);
}
}*/
int lat_translator_init(void)
{
return parse_latencytop_trans();
}
void lat_translator_fini(void)
{
delete_symbols(sym2trans.rb_node);
}