The following commit has been merged into the perf/urgent branch of tip:

Commit-ID:     e98df280bc2a499fd41d7f9e2d6733884de69902
Gitweb:        
https://git.kernel.org/tip/e98df280bc2a499fd41d7f9e2d6733884de69902
Author:        Andi Kleen <[email protected]>
AuthorDate:    Fri, 27 Sep 2019 16:35:44 -07:00
Committer:     Arnaldo Carvalho de Melo <[email protected]>
CommitterDate: Mon, 30 Sep 2019 17:29:52 -03:00

perf script brstackinsn: Fix recovery from LBR/binary mismatch

When the LBR data and the instructions in a binary do not match the loop
printing instructions could get confused and print a long stream of
bogus <bad> instructions.

The problem was that if the instruction decoder cannot decode an
instruction it ilen wasn't initialized, so the loop going through the
basic block would continue with the previous value.

Harden the code to avoid such problems:

- Make sure ilen is always freshly initialized and is 0 for bad
  instructions.

- Do not overrun the code buffer while printing instructions

- Print a warning message if the final jump is not on an instruction
  boundary.

Signed-off-by: Andi Kleen <[email protected]>
Cc: Jiri Olsa <[email protected]>
Link: http://lore.kernel.org/lkml/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
 tools/perf/builtin-script.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 286fc70..67be8d3 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -1063,7 +1063,7 @@ static int perf_sample__fprintf_brstackinsn(struct 
perf_sample *sample,
                        continue;
 
                insn = 0;
-               for (off = 0;; off += ilen) {
+               for (off = 0; off < (unsigned)len; off += ilen) {
                        uint64_t ip = start + off;
 
                        printed += ip__fprintf_sym(ip, thread, x.cpumode, 
x.cpu, &lastsym, attr, fp);
@@ -1074,6 +1074,7 @@ static int perf_sample__fprintf_brstackinsn(struct 
perf_sample *sample,
                                        printed += print_srccode(thread, 
x.cpumode, ip);
                                break;
                        } else {
+                               ilen = 0;
                                printed += fprintf(fp, "\t%016" PRIx64 
"\t%s\n", ip,
                                                   dump_insn(&x, ip, buffer + 
off, len - off, &ilen));
                                if (ilen == 0)
@@ -1083,6 +1084,8 @@ static int perf_sample__fprintf_brstackinsn(struct 
perf_sample *sample,
                                insn++;
                        }
                }
+               if (off != (unsigned)len)
+                       printed += fprintf(fp, "\tmismatch of LBR data and 
executable\n");
        }
 
        /*
@@ -1123,6 +1126,7 @@ static int perf_sample__fprintf_brstackinsn(struct 
perf_sample *sample,
                goto out;
        }
        for (off = 0; off <= end - start; off += ilen) {
+               ilen = 0;
                printed += fprintf(fp, "\t%016" PRIx64 "\t%s\n", start + off,
                                   dump_insn(&x, start + off, buffer + off, len 
- off, &ilen));
                if (ilen == 0)

Reply via email to