aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2012-05-14 04:45:01 -0400
committerIngo Molnar <mingo@kernel.org>2012-05-14 04:45:01 -0400
commit0c5a0f96e82ed73bca017c1c5601a4253cff49df (patch)
treea15295eb3489e9ace0b6c55c595366665e939084
parent5dcefda0fd87fefa440abc9b9d3f1089229f8911 (diff)
parent54e7a4e88eed9ac423e22a259ec51a973fd59bab (diff)
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Arjan & Linus Annotation Edition - Fix indirect calls beautifier, reported by Linus. - Use the objdump comments to nuke specificities about how access to a well know variable is encoded, suggested by Linus. - Show the number of places that jump to a target, requested by Arjan. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--tools/perf/ui/browsers/annotate.c94
-rw-r--r--tools/perf/util/annotate.c303
-rw-r--r--tools/perf/util/annotate.h15
3 files changed, 369 insertions, 43 deletions
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c
index 06367c1df720..6e0ef79be169 100644
--- a/tools/perf/ui/browsers/annotate.c
+++ b/tools/perf/ui/browsers/annotate.c
@@ -16,7 +16,7 @@ struct browser_disasm_line {
16 double percent; 16 double percent;
17 u32 idx; 17 u32 idx;
18 int idx_asm; 18 int idx_asm;
19 bool jump_target; 19 int jump_sources;
20}; 20};
21 21
22struct annotate_browser { 22struct annotate_browser {
@@ -28,11 +28,16 @@ struct annotate_browser {
28 u64 start; 28 u64 start;
29 int nr_asm_entries; 29 int nr_asm_entries;
30 int nr_entries; 30 int nr_entries;
31 int max_jump_sources;
32 int nr_jumps;
31 bool hide_src_code; 33 bool hide_src_code;
32 bool use_offset; 34 bool use_offset;
33 bool jump_arrows; 35 bool jump_arrows;
36 bool show_nr_jumps;
34 bool searching_backwards; 37 bool searching_backwards;
35 u8 addr_width; 38 u8 addr_width;
39 u8 jumps_width;
40 u8 target_width;
36 u8 min_addr_width; 41 u8 min_addr_width;
37 u8 max_addr_width; 42 u8 max_addr_width;
38 char search_bf[128]; 43 char search_bf[128];
@@ -55,6 +60,25 @@ static bool disasm_line__filter(struct ui_browser *browser, void *entry)
55 return false; 60 return false;
56} 61}
57 62
63static int annotate_browser__jumps_percent_color(struct annotate_browser *browser,
64 int nr, bool current)
65{
66 if (current && (!browser->b.use_navkeypressed || browser->b.navkeypressed))
67 return HE_COLORSET_SELECTED;
68 if (nr == browser->max_jump_sources)
69 return HE_COLORSET_TOP;
70 if (nr > 1)
71 return HE_COLORSET_MEDIUM;
72 return HE_COLORSET_NORMAL;
73}
74
75static int annotate_browser__set_jumps_percent_color(struct annotate_browser *browser,
76 int nr, bool current)
77{
78 int color = annotate_browser__jumps_percent_color(browser, nr, current);
79 return ui_browser__set_color(&browser->b, color);
80}
81
58static void annotate_browser__write(struct ui_browser *self, void *entry, int row) 82static void annotate_browser__write(struct ui_browser *self, void *entry, int row)
59{ 83{
60 struct annotate_browser *ab = container_of(self, struct annotate_browser, b); 84 struct annotate_browser *ab = container_of(self, struct annotate_browser, b);
@@ -98,9 +122,20 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro
98 if (!ab->use_offset) { 122 if (!ab->use_offset) {
99 printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr); 123 printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr);
100 } else { 124 } else {
101 if (bdl->jump_target) { 125 if (bdl->jump_sources) {
126 if (ab->show_nr_jumps) {
127 int prev;
128 printed = scnprintf(bf, sizeof(bf), "%*d ",
129 ab->jumps_width,
130 bdl->jump_sources);
131 prev = annotate_browser__set_jumps_percent_color(ab, bdl->jump_sources,
132 current_entry);
133 slsmg_write_nstring(bf, printed);
134 ui_browser__set_color(self, prev);
135 }
136
102 printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ", 137 printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ",
103 ab->addr_width, addr); 138 ab->target_width, addr);
104 } else { 139 } else {
105 printed = scnprintf(bf, sizeof(bf), "%*s ", 140 printed = scnprintf(bf, sizeof(bf), "%*s ",
106 ab->addr_width, " "); 141 ab->addr_width, " ");
@@ -546,10 +581,7 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
546 struct rb_node *nd = NULL; 581 struct rb_node *nd = NULL;
547 struct map_symbol *ms = self->b.priv; 582 struct map_symbol *ms = self->b.priv;
548 struct symbol *sym = ms->sym; 583 struct symbol *sym = ms->sym;
549 const char *help = "<-/ESC: Exit, TAB/shift+TAB: Cycle hot lines, " 584 const char *help = "Press 'h' for help on key bindings";
550 "H: Hottest line, ->/ENTER: Line action, "
551 "O: Offset view, "
552 "S: Source view";
553 int key; 585 int key;
554 586
555 if (ui_browser__show(&self->b, sym->name, help) < 0) 587 if (ui_browser__show(&self->b, sym->name, help) < 0)
@@ -602,26 +634,47 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
602 else 634 else
603 nd = self->curr_hot; 635 nd = self->curr_hot;
604 break; 636 break;
605 case 'H': 637 case K_F1:
606 case 'h': 638 case 'h':
639 ui_browser__help_window(&self->b,
640 "UP/DOWN/PGUP\n"
641 "PGDN/SPACE Navigate\n"
642 "q/ESC/CTRL+C Exit\n\n"
643 "-> Go to target\n"
644 "<- Exit\n"
645 "h Cycle thru hottest instructions\n"
646 "j Toggle showing jump to target arrows\n"
647 "J Toggle showing number of jump sources on targets\n"
648 "n Search next string\n"
649 "o Toggle disassembler output/simplified view\n"
650 "s Toggle source code view\n"
651 "/ Search string\n"
652 "? Search previous string\n");
653 continue;
654 case 'H':
607 nd = self->curr_hot; 655 nd = self->curr_hot;
608 break; 656 break;
609 case 'S':
610 case 's': 657 case 's':
611 if (annotate_browser__toggle_source(self)) 658 if (annotate_browser__toggle_source(self))
612 ui_helpline__puts(help); 659 ui_helpline__puts(help);
613 continue; 660 continue;
614 case 'O':
615 case 'o': 661 case 'o':
616 self->use_offset = !self->use_offset; 662 self->use_offset = !self->use_offset;
617 if (self->use_offset) 663 if (self->use_offset)
618 self->addr_width = self->min_addr_width; 664 self->target_width = self->min_addr_width;
619 else 665 else
620 self->addr_width = self->max_addr_width; 666 self->target_width = self->max_addr_width;
667update_addr_width:
668 self->addr_width = self->target_width;
669 if (self->show_nr_jumps)
670 self->addr_width += self->jumps_width + 1;
621 continue; 671 continue;
622 case 'j': 672 case 'j':
623 self->jump_arrows = !self->jump_arrows; 673 self->jump_arrows = !self->jump_arrows;
624 continue; 674 continue;
675 case 'J':
676 self->show_nr_jumps = !self->show_nr_jumps;
677 goto update_addr_width;
625 case '/': 678 case '/':
626 if (annotate_browser__search(self, delay_secs)) { 679 if (annotate_browser__search(self, delay_secs)) {
627show_help: 680show_help:
@@ -707,11 +760,23 @@ static void annotate_browser__mark_jump_targets(struct annotate_browser *browser
707 continue; 760 continue;
708 761
709 bdlt = disasm_line__browser(dlt); 762 bdlt = disasm_line__browser(dlt);
710 bdlt->jump_target = true; 763 if (++bdlt->jump_sources > browser->max_jump_sources)
764 browser->max_jump_sources = bdlt->jump_sources;
765
766 ++browser->nr_jumps;
711 } 767 }
712 768
713} 769}
714 770
771static inline int width_jumps(int n)
772{
773 if (n >= 100)
774 return 5;
775 if (n / 10)
776 return 2;
777 return 1;
778}
779
715int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, 780int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
716 void(*timer)(void *arg), void *arg, 781 void(*timer)(void *arg), void *arg,
717 int delay_secs) 782 int delay_secs)
@@ -784,8 +849,9 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
784 849
785 annotate_browser__mark_jump_targets(&browser, size); 850 annotate_browser__mark_jump_targets(&browser, size);
786 851
787 browser.addr_width = browser.min_addr_width = hex_width(size); 852 browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size);
788 browser.max_addr_width = hex_width(sym->end); 853 browser.max_addr_width = hex_width(sym->end);
854 browser.jumps_width = width_jumps(browser.max_jump_sources);
789 browser.b.nr_entries = browser.nr_entries; 855 browser.b.nr_entries = browser.nr_entries;
790 browser.b.entries = &notes->src->source, 856 browser.b.entries = &notes->src->source,
791 browser.b.width += 18; /* Percentage */ 857 browser.b.width += 18; /* Percentage */
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
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index bb0a9f27165b..78a5692dd718 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -13,13 +13,26 @@ struct ins;
13struct ins_operands { 13struct ins_operands {
14 char *raw; 14 char *raw;
15 struct { 15 struct {
16 char *raw;
16 char *name; 17 char *name;
17 u64 offset;
18 u64 addr; 18 u64 addr;
19 u64 offset;
19 } target; 20 } target;
21 union {
22 struct {
23 char *raw;
24 char *name;
25 u64 addr;
26 } source;
27 struct {
28 struct ins *ins;
29 struct ins_operands *ops;
30 } locked;
31 };
20}; 32};
21 33
22struct ins_ops { 34struct ins_ops {
35 void (*free)(struct ins_operands *ops);
23 int (*parse)(struct ins_operands *ops); 36 int (*parse)(struct ins_operands *ops);
24 int (*scnprintf)(struct ins *ins, char *bf, size_t size, 37 int (*scnprintf)(struct ins *ins, char *bf, size_t size,
25 struct ins_operands *ops); 38 struct ins_operands *ops);