diff options
| author | Ingo Molnar <mingo@kernel.org> | 2012-05-14 04:45:01 -0400 |
|---|---|---|
| committer | Ingo Molnar <mingo@kernel.org> | 2012-05-14 04:45:01 -0400 |
| commit | 0c5a0f96e82ed73bca017c1c5601a4253cff49df (patch) | |
| tree | a15295eb3489e9ace0b6c55c595366665e939084 | |
| parent | 5dcefda0fd87fefa440abc9b9d3f1089229f8911 (diff) | |
| parent | 54e7a4e88eed9ac423e22a259ec51a973fd59bab (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.c | 94 | ||||
| -rw-r--r-- | tools/perf/util/annotate.c | 303 | ||||
| -rw-r--r-- | tools/perf/util/annotate.h | 15 |
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 | ||
| 22 | struct annotate_browser { | 22 | struct 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 | ||
| 63 | static 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 | |||
| 75 | static 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 | |||
| 58 | static void annotate_browser__write(struct ui_browser *self, void *entry, int row) | 82 | static 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; |
| 667 | update_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)) { |
| 627 | show_help: | 680 | show_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 | ||
| 771 | static 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 | |||
| 715 | int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, | 780 | int 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 = ¬es->src->source, | 856 | browser.b.entries = ¬es->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 | ||
| 19 | const char *disassembler_style; | 19 | const char *disassembler_style; |
| 20 | 20 | ||
| 21 | static struct ins *ins__find(const char *name); | ||
| 22 | static int disasm_line__parse(char *line, char **namep, char **rawp); | ||
| 23 | |||
| 24 | static 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 | |||
| 21 | static int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size, | 32 | static 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 | ||
| 58 | indirect_call: | 69 | indirect_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 | ||
| 136 | static 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 | |||
| 161 | static 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 | |||
| 184 | out_free_ops: | ||
| 185 | free(ops->locked.ops); | ||
| 186 | ops->locked.ops = NULL; | ||
| 187 | return 0; | ||
| 188 | } | ||
| 189 | |||
| 190 | static 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 | |||
| 203 | static 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 | |||
| 210 | static struct ins_ops lock_ops = { | ||
| 211 | .free = lock__delete, | ||
| 212 | .parse = lock__parse, | ||
| 213 | .scnprintf = lock__scnprintf, | ||
| 214 | }; | ||
| 215 | |||
| 216 | static 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 | |||
| 255 | out_free_source: | ||
| 256 | free(ops->source.raw); | ||
| 257 | ops->source.raw = NULL; | ||
| 258 | return -1; | ||
| 259 | } | ||
| 260 | |||
| 261 | static 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 | |||
| 269 | static struct ins_ops mov_ops = { | ||
| 270 | .parse = mov__parse, | ||
| 271 | .scnprintf = mov__scnprintf, | ||
| 272 | }; | ||
| 273 | |||
| 274 | static 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 | |||
| 303 | static 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 | |||
| 310 | static struct ins_ops dec_ops = { | ||
| 311 | .parse = dec__parse, | ||
| 312 | .scnprintf = dec__scnprintf, | ||
| 313 | }; | ||
| 314 | |||
| 116 | static int nop__scnprintf(struct ins *ins __used, char *bf, size_t size, | 315 | static 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 | */ |
| 129 | static struct ins instructions[] = { | 328 | static 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 | ||
| 172 | static int ins__cmp(const void *name, const void *insp) | 404 | static 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 | ||
| 492 | static 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 | |||
| 524 | out_free_name: | ||
| 525 | free(*namep); | ||
| 526 | *namep = NULL; | ||
| 527 | return -1; | ||
| 528 | } | ||
| 529 | |||
| 260 | static struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privsize) | 530 | static 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; | |||
| 13 | struct ins_operands { | 13 | struct 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 | ||
| 22 | struct ins_ops { | 34 | struct 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); |
