These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / tools / perf / tests / code-reading.c
index f671ec3..a767a64 100644 (file)
@@ -33,20 +33,20 @@ static unsigned int hex(char c)
        return c - 'A' + 10;
 }
 
-static void read_objdump_line(const char *line, size_t line_len, void **buf,
-                             size_t *len)
+static size_t read_objdump_line(const char *line, size_t line_len, void *buf,
+                             size_t len)
 {
        const char *p;
-       size_t i;
+       size_t i, j = 0;
 
        /* Skip to a colon */
        p = strchr(line, ':');
        if (!p)
-               return;
+               return 0;
        i = p + 1 - line;
 
        /* Read bytes */
-       while (*len) {
+       while (j < len) {
                char c1, c2;
 
                /* Skip spaces */
@@ -65,20 +65,26 @@ static void read_objdump_line(const char *line, size_t line_len, void **buf,
                if (i < line_len && line[i] && !isspace(line[i]))
                        break;
                /* Store byte */
-               *(unsigned char *)*buf = (hex(c1) << 4) | hex(c2);
-               *buf += 1;
-               *len -= 1;
+               *(unsigned char *)buf = (hex(c1) << 4) | hex(c2);
+               buf += 1;
+               j++;
        }
+       /* return number of successfully read bytes */
+       return j;
 }
 
-static int read_objdump_output(FILE *f, void **buf, size_t *len)
+static int read_objdump_output(FILE *f, void *buf, size_t *len, u64 start_addr)
 {
        char *line = NULL;
-       size_t line_len;
+       size_t line_len, off_last = 0;
        ssize_t ret;
        int err = 0;
+       u64 addr, last_addr = start_addr;
+
+       while (off_last < *len) {
+               size_t off, read_bytes, written_bytes;
+               unsigned char tmp[BUFSZ];
 
-       while (1) {
                ret = getline(&line, &line_len, f);
                if (feof(f))
                        break;
@@ -87,9 +93,33 @@ static int read_objdump_output(FILE *f, void **buf, size_t *len)
                        err = -1;
                        break;
                }
-               read_objdump_line(line, ret, buf, len);
+
+               /* read objdump data into temporary buffer */
+               read_bytes = read_objdump_line(line, ret, tmp, sizeof(tmp));
+               if (!read_bytes)
+                       continue;
+
+               if (sscanf(line, "%"PRIx64, &addr) != 1)
+                       continue;
+               if (addr < last_addr) {
+                       pr_debug("addr going backwards, read beyond section?\n");
+                       break;
+               }
+               last_addr = addr;
+
+               /* copy it from temporary buffer to 'buf' according
+                * to address on current objdump line */
+               off = addr - start_addr;
+               if (off >= *len)
+                       break;
+               written_bytes = MIN(read_bytes, *len - off);
+               memcpy(buf + off, tmp, written_bytes);
+               off_last = off + written_bytes;
        }
 
+       /* len returns number of bytes that could not be read */
+       *len -= off_last;
+
        free(line);
 
        return err;
@@ -103,7 +133,7 @@ static int read_via_objdump(const char *filename, u64 addr, void *buf,
        FILE *f;
        int ret;
 
-       fmt = "%s -d --start-address=0x%"PRIx64" --stop-address=0x%"PRIx64" %s";
+       fmt = "%s -z -d --start-address=0x%"PRIx64" --stop-address=0x%"PRIx64" %s";
        ret = snprintf(cmd, sizeof(cmd), fmt, "objdump", addr, addr + len,
                       filename);
        if (ret <= 0 || (size_t)ret >= sizeof(cmd))
@@ -120,7 +150,7 @@ static int read_via_objdump(const char *filename, u64 addr, void *buf,
                return -1;
        }
 
-       ret = read_objdump_output(f, &buf, &len);
+       ret = read_objdump_output(f, buf, &len, addr);
        if (len) {
                pr_debug("objdump read too few bytes\n");
                if (!ret)
@@ -132,6 +162,18 @@ static int read_via_objdump(const char *filename, u64 addr, void *buf,
        return ret;
 }
 
+static void dump_buf(unsigned char *buf, size_t len)
+{
+       size_t i;
+
+       for (i = 0; i < len; i++) {
+               pr_debug("0x%02x ", buf[i]);
+               if (i % 16 == 15)
+                       pr_debug("\n");
+       }
+       pr_debug("\n");
+}
+
 static int read_object_code(u64 addr, size_t len, u8 cpumode,
                            struct thread *thread, struct state *state)
 {
@@ -234,6 +276,10 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode,
        /* The results should be identical */
        if (memcmp(buf1, buf2, len)) {
                pr_debug("Bytes read differ from those read by objdump\n");
+               pr_debug("buf1 (dso):\n");
+               dump_buf(buf1, len);
+               pr_debug("buf2 (objdump):\n");
+               dump_buf(buf2, len);
                return -1;
        }
        pr_debug("Bytes read match those read by objdump\n");
@@ -248,6 +294,7 @@ static int process_sample_event(struct machine *machine,
        struct perf_sample sample;
        struct thread *thread;
        u8 cpumode;
+       int ret;
 
        if (perf_evlist__parse_sample(evlist, event, &sample)) {
                pr_debug("perf_evlist__parse_sample failed\n");
@@ -262,7 +309,9 @@ static int process_sample_event(struct machine *machine,
 
        cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
 
-       return read_object_code(sample.ip, READLEN, cpumode, thread, state);
+       ret = read_object_code(sample.ip, READLEN, cpumode, thread, state);
+       thread__put(thread);
+       return ret;
 }
 
 static int process_event(struct machine *machine, struct perf_evlist *evlist,
@@ -424,7 +473,7 @@ static int do_test_code_reading(bool try_kcore)
                symbol_conf.kallsyms_name = "/proc/kallsyms";
 
        /* Load kernel map */
-       map = machine->vmlinux_maps[MAP__FUNCTION];
+       map = machine__kernel_map(machine);
        ret = map__load(map, NULL);
        if (ret < 0) {
                pr_debug("map__load failed\n");
@@ -448,7 +497,7 @@ static int do_test_code_reading(bool try_kcore)
        }
 
        ret = perf_event__synthesize_thread_map(NULL, threads,
-                                               perf_event__process, machine, false);
+                                               perf_event__process, machine, false, 500);
        if (ret < 0) {
                pr_debug("perf_event__synthesize_thread_map failed\n");
                goto out_err;
@@ -457,13 +506,13 @@ static int do_test_code_reading(bool try_kcore)
        thread = machine__findnew_thread(machine, pid, pid);
        if (!thread) {
                pr_debug("machine__findnew_thread failed\n");
-               goto out_err;
+               goto out_put;
        }
 
        cpus = cpu_map__new(NULL);
        if (!cpus) {
                pr_debug("cpu_map__new failed\n");
-               goto out_err;
+               goto out_put;
        }
 
        while (1) {
@@ -472,7 +521,7 @@ static int do_test_code_reading(bool try_kcore)
                evlist = perf_evlist__new();
                if (!evlist) {
                        pr_debug("perf_evlist__new failed\n");
-                       goto out_err;
+                       goto out_put;
                }
 
                perf_evlist__set_maps(evlist, cpus, threads);
@@ -482,10 +531,10 @@ static int do_test_code_reading(bool try_kcore)
                else
                        str = "cycles";
                pr_debug("Parsing event '%s'\n", str);
-               ret = parse_events(evlist, str);
+               ret = parse_events(evlist, str, NULL);
                if (ret < 0) {
                        pr_debug("parse_events failed\n");
-                       goto out_err;
+                       goto out_put;
                }
 
                perf_evlist__config(evlist, &opts);
@@ -506,7 +555,7 @@ static int do_test_code_reading(bool try_kcore)
                                continue;
                        }
                        pr_debug("perf_evlist__open failed\n");
-                       goto out_err;
+                       goto out_put;
                }
                break;
        }
@@ -514,7 +563,7 @@ static int do_test_code_reading(bool try_kcore)
        ret = perf_evlist__mmap(evlist, UINT_MAX, false);
        if (ret < 0) {
                pr_debug("perf_evlist__mmap failed\n");
-               goto out_err;
+               goto out_put;
        }
 
        perf_evlist__enable(evlist);
@@ -525,7 +574,7 @@ static int do_test_code_reading(bool try_kcore)
 
        ret = process_events(machine, evlist, &state);
        if (ret < 0)
-               goto out_err;
+               goto out_put;
 
        if (!have_vmlinux && !have_kcore && !try_kcore)
                err = TEST_CODE_READING_NO_KERNEL_OBJ;
@@ -535,12 +584,15 @@ static int do_test_code_reading(bool try_kcore)
                err = TEST_CODE_READING_NO_ACCESS;
        else
                err = TEST_CODE_READING_OK;
+out_put:
+       thread__put(thread);
 out_err:
+
        if (evlist) {
                perf_evlist__delete(evlist);
        } else {
-               cpu_map__delete(cpus);
-               thread_map__delete(threads);
+               cpu_map__put(cpus);
+               thread_map__put(threads);
        }
        machines__destroy_kernel_maps(&machines);
        machine__delete_threads(machine);
@@ -561,16 +613,16 @@ int test__code_reading(void)
        case TEST_CODE_READING_OK:
                return 0;
        case TEST_CODE_READING_NO_VMLINUX:
-               fprintf(stderr, " (no vmlinux)");
+               pr_debug("no vmlinux\n");
                return 0;
        case TEST_CODE_READING_NO_KCORE:
-               fprintf(stderr, " (no kcore)");
+               pr_debug("no kcore\n");
                return 0;
        case TEST_CODE_READING_NO_ACCESS:
-               fprintf(stderr, " (no access)");
+               pr_debug("no access\n");
                return 0;
        case TEST_CODE_READING_NO_KERNEL_OBJ:
-               fprintf(stderr, " (no kernel obj)");
+               pr_debug("no kernel obj\n");
                return 0;
        default:
                return -1;