#include <linux/string.h>
#include <bpf/libbpf.h>
#include <subcmd/parse-options.h>
+#include <subcmd/run-command.h>
/* FIXME: For the HE_COLORSET */
#include "ui/browser.h"
find_target:
target.addr = map__objdump_2mem(map, ops->target.addr);
- if (map_groups__find_ams(&target) == 0 &&
+ if (map_groups__find_ams(map->groups, &target) == 0 &&
map__rip_2objdump(target.map, map->map_ip(target.map, target.addr)) == ops->target.addr)
ops->target.sym = target.sym;
* Actual navigation will come next, with further understanding of how
* the symbol searching and disassembly should be done.
*/
- if (map_groups__find_ams(&target) == 0 &&
+ if (map_groups__find_ams(map->groups, &target) == 0 &&
map__rip_2objdump(target.map, map->map_ip(target.map, target.addr)) == ops->target.addr)
ops->target.sym = target.sym;
ch[offset].start < start)
return 0;
}
+
+ if (ch[offset].num < NUM_SPARKS)
+ ch[offset].cycles_spark[ch[offset].num] = cycles;
+
ch[offset].have_start = have_start;
ch[offset].start = start;
ch[offset].cycles += cycles;
* means that it's not a disassembly line so should be treated differently.
* The ops.raw part will be parsed further according to type of the instruction.
*/
-static int symbol__parse_objdump_line(struct symbol *sym, FILE *file,
+static int symbol__parse_objdump_line(struct symbol *sym,
struct annotate_args *args,
- int *line_nr)
+ char *parsed_line, int *line_nr)
{
struct map *map = args->ms.map;
struct annotation *notes = symbol__annotation(sym);
struct disasm_line *dl;
- char *line = NULL, *parsed_line, *tmp, *tmp2;
- size_t line_len;
+ char *tmp;
s64 line_ip, offset = -1;
regmatch_t match[2];
- if (getline(&line, &line_len, file) < 0)
- return -1;
-
- if (!line)
- return -1;
-
- line_ip = -1;
- parsed_line = strim(line);
-
/* /filename:linenr ? Save line number and ignore. */
if (regexec(&file_lineno, parsed_line, 2, match, 0) == 0) {
*line_nr = atoi(parsed_line + match[1].rm_so);
return 0;
}
- tmp = skip_spaces(parsed_line);
- if (*tmp) {
- /*
- * Parse hexa addresses followed by ':'
- */
- line_ip = strtoull(tmp, &tmp2, 16);
- if (*tmp2 != ':' || tmp == tmp2 || tmp2[1] == '\0')
- line_ip = -1;
- }
-
- if (line_ip != -1) {
+ /* Process hex address followed by ':'. */
+ line_ip = strtoull(parsed_line, &tmp, 16);
+ if (parsed_line != tmp && tmp[0] == ':' && tmp[1] != '\0') {
u64 start = map__rip_2objdump(map, sym->start),
end = map__rip_2objdump(map, sym->end);
if ((u64)line_ip < start || (u64)line_ip >= end)
offset = -1;
else
- parsed_line = tmp2 + 1;
+ parsed_line = tmp + 1;
}
args->offset = offset;
args->ms.sym = sym;
dl = disasm_line__new(args);
- free(line);
(*line_nr)++;
if (dl == NULL)
.addr = dl->ops.target.addr,
};
- if (!map_groups__find_ams(&target) &&
+ if (!map_groups__find_ams(map->groups, &target) &&
target.sym->start == target.al_addr)
dl->ops.target.sym = target.sym;
}
}
}
-int symbol__strerror_disassemble(struct symbol *sym __maybe_unused, struct map *map,
- int errnum, char *buf, size_t buflen)
+int symbol__strerror_disassemble(struct map_symbol *ms, int errnum, char *buf, size_t buflen)
{
- struct dso *dso = map->dso;
+ struct dso *dso = ms->map->dso;
BUG_ON(buflen == 0);
}
#endif // defined(HAVE_LIBBFD_SUPPORT) && defined(HAVE_LIBBPF_SUPPORT)
+/*
+ * Possibly create a new version of line with tabs expanded. Returns the
+ * existing or new line, storage is updated if a new line is allocated. If
+ * allocation fails then NULL is returned.
+ */
+static char *expand_tabs(char *line, char **storage, size_t *storage_len)
+{
+ size_t i, src, dst, len, new_storage_len, num_tabs;
+ char *new_line;
+ size_t line_len = strlen(line);
+
+ for (num_tabs = 0, i = 0; i < line_len; i++)
+ if (line[i] == '\t')
+ num_tabs++;
+
+ if (num_tabs == 0)
+ return line;
+
+ /*
+ * Space for the line and '\0', less the leading and trailing
+ * spaces. Each tab may introduce 7 additional spaces.
+ */
+ new_storage_len = line_len + 1 + (num_tabs * 7);
+
+ new_line = malloc(new_storage_len);
+ if (new_line == NULL) {
+ pr_err("Failure allocating memory for tab expansion\n");
+ return NULL;
+ }
+
+ /*
+ * Copy regions starting at src and expand tabs. If there are two
+ * adjacent tabs then 'src == i', the memcpy is of size 0 and the spaces
+ * are inserted.
+ */
+ for (i = 0, src = 0, dst = 0; i < line_len && num_tabs; i++) {
+ if (line[i] == '\t') {
+ len = i - src;
+ memcpy(&new_line[dst], &line[src], len);
+ dst += len;
+ new_line[dst++] = ' ';
+ while (dst % 8 != 0)
+ new_line[dst++] = ' ';
+ src = i + 1;
+ num_tabs--;
+ }
+ }
+
+ /* Expand the last region. */
+ len = line_len - src;
+ memcpy(&new_line[dst], &line[src], len);
+ dst += len;
+ new_line[dst] = '\0';
+
+ free(*storage);
+ *storage = new_line;
+ *storage_len = new_storage_len;
+ return new_line;
+
+}
+
static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
{
struct annotation_options *opts = args->options;
struct kcore_extract kce;
bool delete_extract = false;
bool decomp = false;
- int stdout_fd[2];
int lineno = 0;
int nline;
- pid_t pid;
+ char *line;
+ size_t line_len;
+ const char *objdump_argv[] = {
+ "/bin/sh",
+ "-c",
+ NULL, /* Will be the objdump command to run. */
+ "--",
+ NULL, /* Will be the symfs path. */
+ NULL,
+ };
+ struct child_process objdump_process;
int err = dso__disassemble_filename(dso, symfs_filename, sizeof(symfs_filename));
if (err)
if (dso__decompress_kmodule_path(dso, symfs_filename,
tmp, sizeof(tmp)) < 0)
- goto out;
+ return -1;
decomp = true;
strcpy(symfs_filename, tmp);
err = asprintf(&command,
"%s %s%s --start-address=0x%016" PRIx64
" --stop-address=0x%016" PRIx64
- " -l -d %s %s -C \"$1\" 2>/dev/null|grep -v \"$1:\"|expand",
+ " -l -d %s %s -C \"$1\"",
opts->objdump_path ?: "objdump",
opts->disassembler_style ? "-M " : "",
opts->disassembler_style ?: "",
map__rip_2objdump(map, sym->start),
map__rip_2objdump(map, sym->end),
- opts->show_asm_raw ? "" : "--no-show-raw",
+ opts->show_asm_raw ? "" : "--no-show-raw-insn",
opts->annotate_src ? "-S" : "");
if (err < 0) {
pr_debug("Executing: %s\n", command);
- err = -1;
- if (pipe(stdout_fd) < 0) {
- pr_err("Failure creating the pipe to run %s\n", command);
- goto out_free_command;
- }
-
- pid = fork();
- if (pid < 0) {
- pr_err("Failure forking to run %s\n", command);
- goto out_close_stdout;
- }
+ objdump_argv[2] = command;
+ objdump_argv[4] = symfs_filename;
- if (pid == 0) {
- close(stdout_fd[0]);
- dup2(stdout_fd[1], 1);
- close(stdout_fd[1]);
- execl("/bin/sh", "sh", "-c", command, "--", symfs_filename,
- NULL);
- perror(command);
- exit(-1);
+ /* Create a pipe to read from for stdout */
+ memset(&objdump_process, 0, sizeof(objdump_process));
+ objdump_process.argv = objdump_argv;
+ objdump_process.out = -1;
+ if (start_command(&objdump_process)) {
+ pr_err("Failure starting to run %s\n", command);
+ err = -1;
+ goto out_free_command;
}
- close(stdout_fd[1]);
-
- file = fdopen(stdout_fd[0], "r");
+ file = fdopen(objdump_process.out, "r");
if (!file) {
pr_err("Failure creating FILE stream for %s\n", command);
/*
* If we were using debug info should retry with
* original binary.
*/
- goto out_free_command;
+ err = -1;
+ goto out_close_stdout;
}
+ /* Storage for getline. */
+ line = NULL;
+ line_len = 0;
+
nline = 0;
while (!feof(file)) {
+ const char *match;
+ char *expanded_line;
+
+ if (getline(&line, &line_len, file) < 0 || !line)
+ break;
+
+ /* Skip lines containing "filename:" */
+ match = strstr(line, symfs_filename);
+ if (match && match[strlen(symfs_filename)] == ':')
+ continue;
+
+ expanded_line = strim(line);
+ expanded_line = expand_tabs(expanded_line, &line, &line_len);
+ if (!expanded_line)
+ break;
+
/*
* The source code line number (lineno) needs to be kept in
* across calls to symbol__parse_objdump_line(), so that it
* can associate it with the instructions till the next one.
* See disasm_line__new() and struct disasm_line::line_nr.
*/
- if (symbol__parse_objdump_line(sym, file, args, &lineno) < 0)
+ if (symbol__parse_objdump_line(sym, args, expanded_line,
+ &lineno) < 0)
break;
nline++;
}
+ free(line);
- if (nline == 0)
+ err = finish_command(&objdump_process);
+ if (err)
+ pr_err("Error running %s\n", command);
+
+ if (nline == 0) {
+ err = -1;
pr_err("No output from %s\n", command);
+ }
/*
* kallsyms does not have symbol sizes so there may a nop at the end.
delete_last_nop(sym);
fclose(file);
- err = 0;
+
+out_close_stdout:
+ close(objdump_process.out);
+
out_free_command:
free(command);
-out_remove_tmp:
- close(stdout_fd[0]);
+out_remove_tmp:
if (decomp)
unlink(symfs_filename);
if (delete_extract)
kcore_extract__delete(&kce);
-out:
- return err;
-out_close_stdout:
- close(stdout_fd[1]);
- goto out_free_command;
+ return err;
}
static void calc_percent(struct sym_hist *sym_hist,
annotation__calc_percent(notes, evsel, symbol__size(sym));
}
-int symbol__annotate(struct symbol *sym, struct map *map,
- struct evsel *evsel, size_t privsize,
- struct annotation_options *options,
- struct arch **parch)
+int symbol__annotate(struct map_symbol *ms, struct evsel *evsel, size_t privsize,
+ struct annotation_options *options, struct arch **parch)
{
+ struct symbol *sym = ms->sym;
struct annotation *notes = symbol__annotation(sym);
struct annotate_args args = {
.privsize = privsize,
}
}
- args.ms.map = map;
- args.ms.sym = sym;
- notes->start = map__rip_2objdump(map, sym->start);
+ args.ms = *ms;
+ notes->start = map__rip_2objdump(ms->map, sym->start);
return symbol__disassemble(sym, &args);
}
return 0;
}
-int symbol__annotate_printf(struct symbol *sym, struct map *map,
- struct evsel *evsel,
+int symbol__annotate_printf(struct map_symbol *ms, struct evsel *evsel,
struct annotation_options *opts)
{
+ struct map *map = ms->map;
+ struct symbol *sym = ms->sym;
struct dso *dso = map->dso;
char *filename;
const char *d_filename;
resort_source_line(root, &tmp_root);
}
-static void symbol__calc_lines(struct symbol *sym, struct map *map,
- struct rb_root *root,
+static void symbol__calc_lines(struct map_symbol *ms, struct rb_root *root,
struct annotation_options *opts)
{
- struct annotation *notes = symbol__annotation(sym);
+ struct annotation *notes = symbol__annotation(ms->sym);
- annotation__calc_lines(notes, map, root, opts);
+ annotation__calc_lines(notes, ms->map, root, opts);
}
-int symbol__tty_annotate2(struct symbol *sym, struct map *map,
- struct evsel *evsel,
+int symbol__tty_annotate2(struct map_symbol *ms, struct evsel *evsel,
struct annotation_options *opts)
{
- struct dso *dso = map->dso;
+ struct dso *dso = ms->map->dso;
+ struct symbol *sym = ms->sym;
struct rb_root source_line = RB_ROOT;
struct hists *hists = evsel__hists(evsel);
char buf[1024];
- if (symbol__annotate2(sym, map, evsel, opts, NULL) < 0)
+ if (symbol__annotate2(ms, evsel, opts, NULL) < 0)
return -1;
if (opts->print_lines) {
srcline_full_filename = opts->full_path;
- symbol__calc_lines(sym, map, &source_line, opts);
+ symbol__calc_lines(ms, &source_line, opts);
print_summary(&source_line, dso->long_name);
}
return 0;
}
-int symbol__tty_annotate(struct symbol *sym, struct map *map,
- struct evsel *evsel,
+int symbol__tty_annotate(struct map_symbol *ms, struct evsel *evsel,
struct annotation_options *opts)
{
- struct dso *dso = map->dso;
+ struct dso *dso = ms->map->dso;
+ struct symbol *sym = ms->sym;
struct rb_root source_line = RB_ROOT;
- if (symbol__annotate(sym, map, evsel, 0, opts, NULL) < 0)
+ if (symbol__annotate(ms, evsel, 0, opts, NULL) < 0)
return -1;
symbol__calc_percent(sym, evsel);
if (opts->print_lines) {
srcline_full_filename = opts->full_path;
- symbol__calc_lines(sym, map, &source_line, opts);
+ symbol__calc_lines(ms, &source_line, opts);
print_summary(&source_line, dso->long_name);
}
- symbol__annotate_printf(sym, map, evsel, opts);
+ symbol__annotate_printf(ms, evsel, opts);
annotated_source__purge(symbol__annotation(sym)->src);
wops->write_graph);
}
-int symbol__annotate2(struct symbol *sym, struct map *map, struct evsel *evsel,
+int symbol__annotate2(struct map_symbol *ms, struct evsel *evsel,
struct annotation_options *options, struct arch **parch)
{
+ struct symbol *sym = ms->sym;
struct annotation *notes = symbol__annotation(sym);
size_t size = symbol__size(sym);
int nr_pcnt = 1, err;
if (perf_evsel__is_group_event(evsel))
nr_pcnt = evsel->core.nr_members;
- err = symbol__annotate(sym, map, evsel, 0, options, parch);
+ err = symbol__annotate(ms, evsel, 0, options, parch);
if (err)
goto out_free_offsets;