aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/annotate.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/annotate.c')
-rw-r--r--tools/perf/util/annotate.c303
1 files changed, 275 insertions, 28 deletions
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 6b4146b40a20..8069dfb5ba77 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -18,6 +18,17 @@
18 18
19const char *disassembler_style; 19const char *disassembler_style;
20 20
21static struct ins *ins__find(const char *name);
22static int disasm_line__parse(char *line, char **namep, char **rawp);
23
24static void ins__delete(struct ins_operands *ops)
25{
26 free(ops->source.raw);
27 free(ops->source.name);
28 free(ops->target.raw);
29 free(ops->target.name);
30}
31
21static int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size, 32static int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size,
22 struct ins_operands *ops) 33 struct ins_operands *ops)
23{ 34{
@@ -56,6 +67,12 @@ static int call__parse(struct ins_operands *ops)
56 return ops->target.name == NULL ? -1 : 0; 67 return ops->target.name == NULL ? -1 : 0;
57 68
58indirect_call: 69indirect_call:
70 tok = strchr(endptr, '(');
71 if (tok != NULL) {
72 ops->target.addr = 0;
73 return 0;
74 }
75
59 tok = strchr(endptr, '*'); 76 tok = strchr(endptr, '*');
60 if (tok == NULL) 77 if (tok == NULL)
61 return -1; 78 return -1;
@@ -70,6 +87,9 @@ static int call__scnprintf(struct ins *ins, char *bf, size_t size,
70 if (ops->target.name) 87 if (ops->target.name)
71 return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->target.name); 88 return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->target.name);
72 89
90 if (ops->target.addr == 0)
91 return ins__raw_scnprintf(ins, bf, size, ops);
92
73 return scnprintf(bf, size, "%-6.6s *%" PRIx64, ins->name, ops->target.addr); 93 return scnprintf(bf, size, "%-6.6s *%" PRIx64, ins->name, ops->target.addr);
74} 94}
75 95
@@ -113,6 +133,185 @@ bool ins__is_jump(const struct ins *ins)
113 return ins->ops == &jump_ops; 133 return ins->ops == &jump_ops;
114} 134}
115 135
136static int comment__symbol(char *raw, char *comment, u64 *addrp, char **namep)
137{
138 char *endptr, *name, *t;
139
140 if (strstr(raw, "(%rip)") == NULL)
141 return 0;
142
143 *addrp = strtoull(comment, &endptr, 16);
144 name = strchr(endptr, '<');
145 if (name == NULL)
146 return -1;
147
148 name++;
149
150 t = strchr(name, '>');
151 if (t == NULL)
152 return 0;
153
154 *t = '\0';
155 *namep = strdup(name);
156 *t = '>';
157
158 return 0;
159}
160
161static int lock__parse(struct ins_operands *ops)
162{
163 char *name;
164
165 ops->locked.ops = zalloc(sizeof(*ops->locked.ops));
166 if (ops->locked.ops == NULL)
167 return 0;
168
169 if (disasm_line__parse(ops->raw, &name, &ops->locked.ops->raw) < 0)
170 goto out_free_ops;
171
172 ops->locked.ins = ins__find(name);
173 if (ops->locked.ins == NULL)
174 goto out_free_ops;
175
176 if (!ops->locked.ins->ops)
177 return 0;
178
179 if (ops->locked.ins->ops->parse)
180 ops->locked.ins->ops->parse(ops->locked.ops);
181
182 return 0;
183
184out_free_ops:
185 free(ops->locked.ops);
186 ops->locked.ops = NULL;
187 return 0;
188}
189
190static int lock__scnprintf(struct ins *ins, char *bf, size_t size,
191 struct ins_operands *ops)
192{
193 int printed;
194
195 if (ops->locked.ins == NULL)
196 return ins__raw_scnprintf(ins, bf, size, ops);
197
198 printed = scnprintf(bf, size, "%-6.6s ", ins->name);
199 return printed + ins__scnprintf(ops->locked.ins, bf + printed,
200 size - printed, ops->locked.ops);
201}
202
203static void lock__delete(struct ins_operands *ops)
204{
205 free(ops->locked.ops);
206 free(ops->target.raw);
207 free(ops->target.name);
208}
209
210static struct ins_ops lock_ops = {
211 .free = lock__delete,
212 .parse = lock__parse,
213 .scnprintf = lock__scnprintf,
214};
215
216static int mov__parse(struct ins_operands *ops)
217{
218 char *s = strchr(ops->raw, ','), *target, *comment, prev;
219
220 if (s == NULL)
221 return -1;
222
223 *s = '\0';
224 ops->source.raw = strdup(ops->raw);
225 *s = ',';
226
227 if (ops->source.raw == NULL)
228 return -1;
229
230 target = ++s;
231
232 while (s[0] != '\0' && !isspace(s[0]))
233 ++s;
234 prev = *s;
235 *s = '\0';
236
237 ops->target.raw = strdup(target);
238 *s = prev;
239
240 if (ops->target.raw == NULL)
241 goto out_free_source;
242
243 comment = strchr(s, '#');
244 if (comment == NULL)
245 return 0;
246
247 while (comment[0] != '\0' && isspace(comment[0]))
248 ++comment;
249
250 comment__symbol(ops->source.raw, comment, &ops->source.addr, &ops->source.name);
251 comment__symbol(ops->target.raw, comment, &ops->target.addr, &ops->target.name);
252
253 return 0;
254
255out_free_source:
256 free(ops->source.raw);
257 ops->source.raw = NULL;
258 return -1;
259}
260
261static int mov__scnprintf(struct ins *ins, char *bf, size_t size,
262 struct ins_operands *ops)
263{
264 return scnprintf(bf, size, "%-6.6s %s,%s", ins->name,
265 ops->source.name ?: ops->source.raw,
266 ops->target.name ?: ops->target.raw);
267}
268
269static struct ins_ops mov_ops = {
270 .parse = mov__parse,
271 .scnprintf = mov__scnprintf,
272};
273
274static int dec__parse(struct ins_operands *ops)
275{
276 char *target, *comment, *s, prev;
277
278 target = s = ops->raw;
279
280 while (s[0] != '\0' && !isspace(s[0]))
281 ++s;
282 prev = *s;
283 *s = '\0';
284
285 ops->target.raw = strdup(target);
286 *s = prev;
287
288 if (ops->target.raw == NULL)
289 return -1;
290
291 comment = strchr(s, '#');
292 if (comment == NULL)
293 return 0;
294
295 while (comment[0] != '\0' && isspace(comment[0]))
296 ++comment;
297
298 comment__symbol(ops->target.raw, comment, &ops->target.addr, &ops->target.name);
299
300 return 0;
301}
302
303static int dec__scnprintf(struct ins *ins, char *bf, size_t size,
304 struct ins_operands *ops)
305{
306 return scnprintf(bf, size, "%-6.6s %s", ins->name,
307 ops->target.name ?: ops->target.raw);
308}
309
310static struct ins_ops dec_ops = {
311 .parse = dec__parse,
312 .scnprintf = dec__scnprintf,
313};
314
116static int nop__scnprintf(struct ins *ins __used, char *bf, size_t size, 315static int nop__scnprintf(struct ins *ins __used, char *bf, size_t size,
117 struct ins_operands *ops __used) 316 struct ins_operands *ops __used)
118{ 317{
@@ -127,8 +326,25 @@ static struct ins_ops nop_ops = {
127 * Must be sorted by name! 326 * Must be sorted by name!
128 */ 327 */
129static struct ins instructions[] = { 328static struct ins instructions[] = {
329 { .name = "add", .ops = &mov_ops, },
330 { .name = "addl", .ops = &mov_ops, },
331 { .name = "addq", .ops = &mov_ops, },
332 { .name = "addw", .ops = &mov_ops, },
333 { .name = "and", .ops = &mov_ops, },
334 { .name = "bts", .ops = &mov_ops, },
130 { .name = "call", .ops = &call_ops, }, 335 { .name = "call", .ops = &call_ops, },
131 { .name = "callq", .ops = &call_ops, }, 336 { .name = "callq", .ops = &call_ops, },
337 { .name = "cmp", .ops = &mov_ops, },
338 { .name = "cmpb", .ops = &mov_ops, },
339 { .name = "cmpl", .ops = &mov_ops, },
340 { .name = "cmpq", .ops = &mov_ops, },
341 { .name = "cmpw", .ops = &mov_ops, },
342 { .name = "cmpxch", .ops = &mov_ops, },
343 { .name = "dec", .ops = &dec_ops, },
344 { .name = "decl", .ops = &dec_ops, },
345 { .name = "imul", .ops = &mov_ops, },
346 { .name = "inc", .ops = &dec_ops, },
347 { .name = "incl", .ops = &dec_ops, },
132 { .name = "ja", .ops = &jump_ops, }, 348 { .name = "ja", .ops = &jump_ops, },
133 { .name = "jae", .ops = &jump_ops, }, 349 { .name = "jae", .ops = &jump_ops, },
134 { .name = "jb", .ops = &jump_ops, }, 350 { .name = "jb", .ops = &jump_ops, },
@@ -164,9 +380,25 @@ static struct ins instructions[] = {
164 { .name = "jrcxz", .ops = &jump_ops, }, 380 { .name = "jrcxz", .ops = &jump_ops, },
165 { .name = "js", .ops = &jump_ops, }, 381 { .name = "js", .ops = &jump_ops, },
166 { .name = "jz", .ops = &jump_ops, }, 382 { .name = "jz", .ops = &jump_ops, },
383 { .name = "lea", .ops = &mov_ops, },
384 { .name = "lock", .ops = &lock_ops, },
385 { .name = "mov", .ops = &mov_ops, },
386 { .name = "movb", .ops = &mov_ops, },
387 { .name = "movdqa",.ops = &mov_ops, },
388 { .name = "movl", .ops = &mov_ops, },
389 { .name = "movq", .ops = &mov_ops, },
390 { .name = "movslq", .ops = &mov_ops, },
391 { .name = "movzbl", .ops = &mov_ops, },
392 { .name = "movzwl", .ops = &mov_ops, },
167 { .name = "nop", .ops = &nop_ops, }, 393 { .name = "nop", .ops = &nop_ops, },
168 { .name = "nopl", .ops = &nop_ops, }, 394 { .name = "nopl", .ops = &nop_ops, },
169 { .name = "nopw", .ops = &nop_ops, }, 395 { .name = "nopw", .ops = &nop_ops, },
396 { .name = "or", .ops = &mov_ops, },
397 { .name = "orl", .ops = &mov_ops, },
398 { .name = "test", .ops = &mov_ops, },
399 { .name = "testb", .ops = &mov_ops, },
400 { .name = "testl", .ops = &mov_ops, },
401 { .name = "xadd", .ops = &mov_ops, },
170}; 402};
171 403
172static int ins__cmp(const void *name, const void *insp) 404static int ins__cmp(const void *name, const void *insp)
@@ -257,6 +489,44 @@ static void disasm_line__init_ins(struct disasm_line *dl)
257 dl->ins->ops->parse(&dl->ops); 489 dl->ins->ops->parse(&dl->ops);
258} 490}
259 491
492static int disasm_line__parse(char *line, char **namep, char **rawp)
493{
494 char *name = line, tmp;
495
496 while (isspace(name[0]))
497 ++name;
498
499 if (name[0] == '\0')
500 return -1;
501
502 *rawp = name + 1;
503
504 while ((*rawp)[0] != '\0' && !isspace((*rawp)[0]))
505 ++*rawp;
506
507 tmp = (*rawp)[0];
508 (*rawp)[0] = '\0';
509 *namep = strdup(name);
510
511 if (*namep == NULL)
512 goto out_free_name;
513
514 (*rawp)[0] = tmp;
515
516 if ((*rawp)[0] != '\0') {
517 (*rawp)++;
518 while (isspace((*rawp)[0]))
519 ++(*rawp);
520 }
521
522 return 0;
523
524out_free_name:
525 free(*namep);
526 *namep = NULL;
527 return -1;
528}
529
260static struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privsize) 530static struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privsize)
261{ 531{
262 struct disasm_line *dl = zalloc(sizeof(*dl) + privsize); 532 struct disasm_line *dl = zalloc(sizeof(*dl) + privsize);
@@ -268,35 +538,9 @@ static struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privs
268 goto out_delete; 538 goto out_delete;
269 539
270 if (offset != -1) { 540 if (offset != -1) {
271 char *name = dl->line, tmp; 541 if (disasm_line__parse(dl->line, &dl->name, &dl->ops.raw) < 0)
272
273 while (isspace(name[0]))
274 ++name;
275
276 if (name[0] == '\0')
277 goto out_delete;
278
279 dl->ops.raw = name + 1;
280
281 while (dl->ops.raw[0] != '\0' &&
282 !isspace(dl->ops.raw[0]))
283 ++dl->ops.raw;
284
285 tmp = dl->ops.raw[0];
286 dl->ops.raw[0] = '\0';
287 dl->name = strdup(name);
288
289 if (dl->name == NULL)
290 goto out_free_line; 542 goto out_free_line;
291 543
292 dl->ops.raw[0] = tmp;
293
294 if (dl->ops.raw[0] != '\0') {
295 dl->ops.raw++;
296 while (isspace(dl->ops.raw[0]))
297 ++dl->ops.raw;
298 }
299
300 disasm_line__init_ins(dl); 544 disasm_line__init_ins(dl);
301 } 545 }
302 } 546 }
@@ -314,7 +558,10 @@ void disasm_line__free(struct disasm_line *dl)
314{ 558{
315 free(dl->line); 559 free(dl->line);
316 free(dl->name); 560 free(dl->name);
317 free(dl->ops.target.name); 561 if (dl->ins && dl->ins->ops->free)
562 dl->ins->ops->free(&dl->ops);
563 else
564 ins__delete(&dl->ops);
318 free(dl); 565 free(dl);
319} 566}
320 567