Merge tag 'trace-seq-buf-3.19' of git://git.kernel.org/pub/scm/linux/kernel/git/roste...
[cascardo/linux.git] / arch / x86 / kernel / cpu / perf_event_intel_lbr.c
index 45fa730..58f1a94 100644 (file)
@@ -465,7 +465,7 @@ static int branch_type(unsigned long from, unsigned long to, int abort)
 {
        struct insn insn;
        void *addr;
-       int bytes, size = MAX_INSN_SIZE;
+       int bytes_read, bytes_left;
        int ret = X86_BR_NONE;
        int ext, to_plm, from_plm;
        u8 buf[MAX_INSN_SIZE];
@@ -493,8 +493,10 @@ static int branch_type(unsigned long from, unsigned long to, int abort)
                        return X86_BR_NONE;
 
                /* may fail if text not present */
-               bytes = copy_from_user_nmi(buf, (void __user *)from, size);
-               if (bytes != 0)
+               bytes_left = copy_from_user_nmi(buf, (void __user *)from,
+                                               MAX_INSN_SIZE);
+               bytes_read = MAX_INSN_SIZE - bytes_left;
+               if (!bytes_read)
                        return X86_BR_NONE;
 
                addr = buf;
@@ -505,10 +507,19 @@ static int branch_type(unsigned long from, unsigned long to, int abort)
                 * Ensure we don't blindy read any address by validating it is
                 * a known text address.
                 */
-               if (kernel_text_address(from))
+               if (kernel_text_address(from)) {
                        addr = (void *)from;
-               else
+                       /*
+                        * Assume we can get the maximum possible size
+                        * when grabbing kernel data.  This is not
+                        * _strictly_ true since we could possibly be
+                        * executing up next to a memory hole, but
+                        * it is very unlikely to be a problem.
+                        */
+                       bytes_read = MAX_INSN_SIZE;
+               } else {
                        return X86_BR_NONE;
+               }
        }
 
        /*
@@ -518,8 +529,10 @@ static int branch_type(unsigned long from, unsigned long to, int abort)
 #ifdef CONFIG_X86_64
        is64 = kernel_ip((unsigned long)addr) || !test_thread_flag(TIF_IA32);
 #endif
-       insn_init(&insn, addr, is64);
+       insn_init(&insn, addr, bytes_read, is64);
        insn_get_opcode(&insn);
+       if (!insn.opcode.got)
+               return X86_BR_ABORT;
 
        switch (insn.opcode.bytes[0]) {
        case 0xf: