All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 1/2] x86/traps: Prevent interleaving of concurrent cpu state dumps
@ 2016-02-11 10:52 Andrew Cooper
  2016-02-11 10:52 ` [PATCH v2 2/2] x86/traps: Dump instruction stream in show_execution_state() Andrew Cooper
  0 siblings, 1 reply; 8+ messages in thread
From: Andrew Cooper @ 2016-02-11 10:52 UTC (permalink / raw)
  To: Xen-devel; +Cc: Andrew Cooper, Tim Deegan, Ian Campbell, Jan Beulich

If two cpus enter show_execution_state() concurrently, the resulting console
output interleaved, and of no help debugging the situation further.

As calls to these locations are rare and usually important, it is acceptable
to serialise them.  These codepaths are also on the terminal error paths, so
the console lock must be the lock used for serialisation, to allow
console_force_unlock() to function properly.

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
---
CC: Jan Beulich <JBeulich@suse.com>
CC: Tim Deegan <tim@xen.org>
CC: Ian Campbell <Ian.Campbell@citrix.com>

v2: Use the console lock rather than a local lock to allow
console_force_unlock() to function correctly on terminal error paths.
---
 xen/arch/x86/traps.c       | 12 ++++++++++++
 xen/drivers/char/console.c | 16 ++++++++++++++++
 xen/include/xen/console.h  |  2 ++
 3 files changed, 30 insertions(+)

diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c
index d19250a..ab7deee 100644
--- a/xen/arch/x86/traps.c
+++ b/xen/arch/x86/traps.c
@@ -416,12 +416,19 @@ void show_stack_overflow(unsigned int cpu, const struct cpu_user_regs *regs)
 
 void show_execution_state(const struct cpu_user_regs *regs)
 {
+    /* Prevent interleaving of output. */
+    unsigned long flags = console_lock_recursive_irqsave();
+
     show_registers(regs);
     show_stack(regs);
+
+    console_unlock_recursive_irqrestore(flags);
 }
 
 void vcpu_show_execution_state(struct vcpu *v)
 {
+    unsigned long flags;
+
     printk("*** Dumping Dom%d vcpu#%d state: ***\n",
            v->domain->domain_id, v->vcpu_id);
 
@@ -433,10 +440,15 @@ void vcpu_show_execution_state(struct vcpu *v)
 
     vcpu_pause(v); /* acceptably dangerous */
 
+    /* Prevent interleaving of output. */
+    flags = console_lock_recursive_irqsave();
+
     vcpu_show_registers(v);
     if ( guest_kernel_mode(v, &v->arch.user_regs) )
         show_guest_stack(v, &v->arch.user_regs);
 
+    console_unlock_recursive_irqrestore(flags);
+
     vcpu_unpause(v);
 }
 
diff --git a/xen/drivers/char/console.c b/xen/drivers/char/console.c
index e0083f1..f4f6141 100644
--- a/xen/drivers/char/console.c
+++ b/xen/drivers/char/console.c
@@ -865,6 +865,22 @@ void console_end_log_everything(void)
     atomic_dec(&print_everything);
 }
 
+unsigned long console_lock_recursive_irqsave(void)
+{
+    unsigned long flags;
+
+    local_irq_save(flags);
+    spin_lock_recursive(&console_lock);
+
+    return flags;
+}
+
+void console_unlock_recursive_irqrestore(unsigned long flags)
+{
+    spin_unlock_recursive(&console_lock);
+    local_irq_restore(flags);
+}
+
 void console_force_unlock(void)
 {
     watchdog_disable();
diff --git a/xen/include/xen/console.h b/xen/include/xen/console.h
index c7fd9ca..ea06fd8 100644
--- a/xen/include/xen/console.h
+++ b/xen/include/xen/console.h
@@ -21,6 +21,8 @@ int console_has(const char *device);
 
 int fill_console_start_info(struct dom0_vga_console_info *);
 
+unsigned long console_lock_recursive_irqsave(void);
+void console_unlock_recursive_irqrestore(unsigned long flags);
 void console_force_unlock(void);
 
 void console_start_sync(void);
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 2/2] x86/traps: Dump instruction stream in show_execution_state()
  2016-02-11 10:52 [PATCH v2 1/2] x86/traps: Prevent interleaving of concurrent cpu state dumps Andrew Cooper
@ 2016-02-11 10:52 ` Andrew Cooper
  2016-02-11 11:16   ` Jan Beulich
  2016-02-11 14:33   ` [PATCH v3 " Andrew Cooper
  0 siblings, 2 replies; 8+ messages in thread
From: Andrew Cooper @ 2016-02-11 10:52 UTC (permalink / raw)
  To: Xen-devel; +Cc: Andrew Cooper, Jan Beulich

For first pass triage of crashes, it is useful to have the instruction
stream present, especially now that Xen binary patches itself.

A sample output now looks like:

(XEN) ----[ Xen-4.7-unstable  x86_64  debug=y  Not tainted ]----
(XEN) CPU:    0
(XEN) RIP:    e008:[<ffff82d0801607e4>] default_idle+0x76/0x7b
(XEN) RFLAGS: 0000000000000246   CONTEXT: hypervisor
(XEN) rax: ffff82d080331030   rbx: ffff83007fce8000   rcx: 0000000000000000
(XEN) rdx: 0000000000000000   rsi: ffff82d080331b98   rdi: 0000000000000000
(XEN) rbp: ffff83007fcefef0   rsp: ffff83007fcefef0   r8:  ffff83007faf8118
(XEN) r9:  00000009983e89fd   r10: 00000009983e89fd   r11: 0000000000000246
(XEN) r12: ffff83007fd61000   r13: 00000000ffffffff   r14: ffff83007fad9000
(XEN) r15: ffff83007fae3000   cr0: 000000008005003b   cr4: 00000000000026e0
(XEN) cr3: 000000007fc9b000   cr2: 00007f70976b3fed
(XEN) ds: 0000   es: 0000   fs: 0000   gs: 0000   ss: e010   cs: e008
(XEN) Xen code around <ffff82d0801607e4> (default_idle+0x76/0x7b):
(XEN)  83 3c 10 00 75 04 fb f4 <eb> 01 fb 5d c3 55 48 89 e5 3b 3d 0d 50 12 00 72
(XEN) Xen stack trace from rsp=ffff83007fcefef0:
(XEN)    ffff83007fceff10 ffff82d080160e08 ffff82d08012c40a ffff83007faf9000
(XEN)    ffff83007fcefdd8 ffffffff81a01fd8 ffff88002f07d4c0 ffffffff81a01fd8
(XEN)    0000000000000000 ffffffff81a01e58 ffffffff81a01fd8 0000000000000246
(XEN)    00000000ffff0052 0000000000000000 0000000000000000 0000000000000000
(XEN)    ffffffff810013aa 0000000000000001 00000000deadbeef 00000000deadbeef
(XEN)    0000010000000000 ffffffff810013aa 000000000000e033 0000000000000246
(XEN)    ffffffff81a01e40 000000000000e02b 0000000000000000 0000000000000000
(XEN)    0000000000000000 0000000000000000 0000000000000000 ffff83007faf9000
(XEN)    0000000000000000 0000000000000000
(XEN) Xen call trace:
(XEN)    [<ffff82d0801607e4>] default_idle+0x76/0x7b
(XEN)    [<ffff82d080160e08>] idle_loop+0x51/0x6e
(XEN)

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
---
CC: Jan Beulich <JBeulich@suse.com>

v2: Deal with %rip wrapping.  In such a case, insert dashes into printed line.
---
 xen/arch/x86/traps.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 51 insertions(+)

diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c
index ab7deee..5146e69 100644
--- a/xen/arch/x86/traps.c
+++ b/xen/arch/x86/traps.c
@@ -114,6 +114,56 @@ boolean_param("ler", opt_ler);
 #define stack_words_per_line 4
 #define ESP_BEFORE_EXCEPTION(regs) ((unsigned long *)regs->rsp)
 
+static void show_code(const struct cpu_user_regs *regs)
+{
+    unsigned char insns_before[8], insns_after[16];
+    unsigned int i, missing_before, missing_after;
+
+    if ( guest_mode(regs) )
+        return;
+
+    /*
+     * This dance with {insns,missing}_{before,after} is to ensure that, if
+     * %rip -8/+16 wraps around a bounday, we read a non-wrapped regs->rip
+     * pointer, and calculate which bytes were not read so they may be
+     * replaced with dashes in the printed output.
+     */
+    missing_before = __copy_from_user(
+        insns_before, (void __user *)regs->rip - 8, ARRAY_SIZE(insns_before));
+    missing_after = __copy_from_user(
+        insns_after, (void __user *)regs->rip, ARRAY_SIZE(insns_after));
+
+    printk("Xen code around <%p> (%ps)%s:\n",
+           _p(regs->rip), _p(regs->rip),
+           (missing_before || missing_after) ? " [fault on access]" : "");
+
+    /* Print bytes from insns_before[]. */
+    for ( i = 0; i < ARRAY_SIZE(insns_before); ++i )
+    {
+        if ( i < (ARRAY_SIZE(insns_before) - missing_before) )
+            printk(" %02x", insns_before[i]);
+        else
+            printk(" --");
+    }
+
+    /* Print the byte under %rip. */
+    if ( missing_after != ARRAY_SIZE(insns_after) )
+        printk(" <%02x>", insns_after[0]);
+    else
+        printk(" <-->");
+
+    /* Print bytes from insns_after[]. */
+    for ( i = 1; i < ARRAY_SIZE(insns_after); ++i )
+    {
+        if ( i < (ARRAY_SIZE(insns_after) - missing_after) )
+            printk(" %02x", insns_after[i]);
+        else
+            printk(" --");
+    }
+
+    printk("\n");
+}
+
 static void show_guest_stack(struct vcpu *v, const struct cpu_user_regs *regs)
 {
     int i;
@@ -420,6 +470,7 @@ void show_execution_state(const struct cpu_user_regs *regs)
     unsigned long flags = console_lock_recursive_irqsave();
 
     show_registers(regs);
+    show_code(regs);
     show_stack(regs);
 
     console_unlock_recursive_irqrestore(flags);
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 2/2] x86/traps: Dump instruction stream in show_execution_state()
  2016-02-11 10:52 ` [PATCH v2 2/2] x86/traps: Dump instruction stream in show_execution_state() Andrew Cooper
@ 2016-02-11 11:16   ` Jan Beulich
  2016-02-11 12:12     ` Andrew Cooper
  2016-02-11 14:33   ` [PATCH v3 " Andrew Cooper
  1 sibling, 1 reply; 8+ messages in thread
From: Jan Beulich @ 2016-02-11 11:16 UTC (permalink / raw)
  To: Andrew Cooper; +Cc: Xen-devel

>>> On 11.02.16 at 11:52, <andrew.cooper3@citrix.com> wrote:
> v2: Deal with %rip wrapping.  In such a case, insert dashes into printed 
> line.

I don't think this deals with wrapping now, since ...

> --- a/xen/arch/x86/traps.c
> +++ b/xen/arch/x86/traps.c
> @@ -114,6 +114,56 @@ boolean_param("ler", opt_ler);
>  #define stack_words_per_line 4
>  #define ESP_BEFORE_EXCEPTION(regs) ((unsigned long *)regs->rsp)
>  
> +static void show_code(const struct cpu_user_regs *regs)
> +{
> +    unsigned char insns_before[8], insns_after[16];
> +    unsigned int i, missing_before, missing_after;
> +
> +    if ( guest_mode(regs) )
> +        return;
> +
> +    /*
> +     * This dance with {insns,missing}_{before,after} is to ensure that, if
> +     * %rip -8/+16 wraps around a bounday, we read a non-wrapped regs->rip
> +     * pointer, and calculate which bytes were not read so they may be
> +     * replaced with dashes in the printed output.
> +     */
> +    missing_before = __copy_from_user(
> +        insns_before, (void __user *)regs->rip - 8, ARRAY_SIZE(insns_before));
> +    missing_after = __copy_from_user(
> +        insns_after, (void __user *)regs->rip, ARRAY_SIZE(insns_after));

... iirc __copy_from_user() doesn't range check the addresses.
Also reading the leading bytes is done in kind of a strange way: It'll
read initial bytes (farther away from RIP) and perhaps not read
later ones (closer to RIP), albeit clearly the ones closer are of more
interest. In the extreme case, where RIP is only a few bytes into a
page following an unmapped one, no leading bytes would be printed
at all despite some actually being readable.

Avoiding actual wrapping could be easily done by extending the
guest_mode() check above to also range check RIP against the
hypervisor image boundaries (post-boot this could even be limited
further, but perhaps using the full XEN_VIRT_{START,END} range is
the better route with xSplice in mind.

And then there's a literal 8 left in the first function invocation
above, which imo would better also be ARRAY_SIZE(insns_before)
(albeit with the comment above this invocation is going to change
anyway).

Jan

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 2/2] x86/traps: Dump instruction stream in show_execution_state()
  2016-02-11 11:16   ` Jan Beulich
@ 2016-02-11 12:12     ` Andrew Cooper
  2016-02-11 12:52       ` Jan Beulich
  0 siblings, 1 reply; 8+ messages in thread
From: Andrew Cooper @ 2016-02-11 12:12 UTC (permalink / raw)
  To: Jan Beulich; +Cc: Xen-devel

On 11/02/16 11:16, Jan Beulich wrote:
>>>> On 11.02.16 at 11:52, <andrew.cooper3@citrix.com> wrote:
>> v2: Deal with %rip wrapping.  In such a case, insert dashes into printed 
>> line.
> I don't think this deals with wrapping now, since ...
>
>> --- a/xen/arch/x86/traps.c
>> +++ b/xen/arch/x86/traps.c
>> @@ -114,6 +114,56 @@ boolean_param("ler", opt_ler);
>>  #define stack_words_per_line 4
>>  #define ESP_BEFORE_EXCEPTION(regs) ((unsigned long *)regs->rsp)
>>  
>> +static void show_code(const struct cpu_user_regs *regs)
>> +{
>> +    unsigned char insns_before[8], insns_after[16];
>> +    unsigned int i, missing_before, missing_after;
>> +
>> +    if ( guest_mode(regs) )
>> +        return;
>> +
>> +    /*
>> +     * This dance with {insns,missing}_{before,after} is to ensure that, if
>> +     * %rip -8/+16 wraps around a bounday, we read a non-wrapped regs->rip
>> +     * pointer, and calculate which bytes were not read so they may be
>> +     * replaced with dashes in the printed output.
>> +     */
>> +    missing_before = __copy_from_user(
>> +        insns_before, (void __user *)regs->rip - 8, ARRAY_SIZE(insns_before));
>> +    missing_after = __copy_from_user(
>> +        insns_after, (void __user *)regs->rip, ARRAY_SIZE(insns_after));
> ... iirc __copy_from_user() doesn't range check the addresses.
> Also reading the leading bytes is done in kind of a strange way: It'll
> read initial bytes (farther away from RIP) and perhaps not read
> later ones (closer to RIP), albeit clearly the ones closer are of more
> interest. In the extreme case, where RIP is only a few bytes into a
> page following an unmapped one, no leading bytes would be printed
> at all despite some actually being readable.

I think in this specific case, it might be best to hand roll some asm
using rep movs and the direction flag, with manual fault handling.

>
> Avoiding actual wrapping could be easily done by extending the
> guest_mode() check above to also range check RIP against the
> hypervisor image boundaries (post-boot this could even be limited
> further, but perhaps using the full XEN_VIRT_{START,END} range is
> the better route with xSplice in mind.

I would like, where possible, to avoid omitting the instruction stream
if Xen is outside of its expected boundaries.

~Andrew

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 2/2] x86/traps: Dump instruction stream in show_execution_state()
  2016-02-11 12:12     ` Andrew Cooper
@ 2016-02-11 12:52       ` Jan Beulich
  2016-02-11 13:41         ` Andrew Cooper
  0 siblings, 1 reply; 8+ messages in thread
From: Jan Beulich @ 2016-02-11 12:52 UTC (permalink / raw)
  To: Andrew Cooper; +Cc: Xen-devel

>>> On 11.02.16 at 13:12, <andrew.cooper3@citrix.com> wrote:
> On 11/02/16 11:16, Jan Beulich wrote:
>>>>> On 11.02.16 at 11:52, <andrew.cooper3@citrix.com> wrote:
>>> --- a/xen/arch/x86/traps.c
>>> +++ b/xen/arch/x86/traps.c
>>> @@ -114,6 +114,56 @@ boolean_param("ler", opt_ler);
>>>  #define stack_words_per_line 4
>>>  #define ESP_BEFORE_EXCEPTION(regs) ((unsigned long *)regs->rsp)
>>>  
>>> +static void show_code(const struct cpu_user_regs *regs)
>>> +{
>>> +    unsigned char insns_before[8], insns_after[16];
>>> +    unsigned int i, missing_before, missing_after;
>>> +
>>> +    if ( guest_mode(regs) )
>>> +        return;
>>> +
>>> +    /*
>>> +     * This dance with {insns,missing}_{before,after} is to ensure that, if
>>> +     * %rip -8/+16 wraps around a bounday, we read a non-wrapped regs->rip
>>> +     * pointer, and calculate which bytes were not read so they may be
>>> +     * replaced with dashes in the printed output.
>>> +     */
>>> +    missing_before = __copy_from_user(
>>> +        insns_before, (void __user *)regs->rip - 8, ARRAY_SIZE(insns_before));
>>> +    missing_after = __copy_from_user(
>>> +        insns_after, (void __user *)regs->rip, ARRAY_SIZE(insns_after));
>> ... iirc __copy_from_user() doesn't range check the addresses.
>> Also reading the leading bytes is done in kind of a strange way: It'll
>> read initial bytes (farther away from RIP) and perhaps not read
>> later ones (closer to RIP), albeit clearly the ones closer are of more
>> interest. In the extreme case, where RIP is only a few bytes into a
>> page following an unmapped one, no leading bytes would be printed
>> at all despite some actually being readable.
> 
> I think in this specific case, it might be best to hand roll some asm
> using rep movs and the direction flag, with manual fault handling.

That's certainly an option.

>> Avoiding actual wrapping could be easily done by extending the
>> guest_mode() check above to also range check RIP against the
>> hypervisor image boundaries (post-boot this could even be limited
>> further, but perhaps using the full XEN_VIRT_{START,END} range is
>> the better route with xSplice in mind.
> 
> I would like, where possible, to avoid omitting the instruction stream
> if Xen is outside of its expected boundaries.

Which is because of ...? What useful information do you think can
be gained from the actual instruction when the mere fact of being
outside the boundaries is a bug?

Jan

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 2/2] x86/traps: Dump instruction stream in show_execution_state()
  2016-02-11 12:52       ` Jan Beulich
@ 2016-02-11 13:41         ` Andrew Cooper
  2016-02-11 13:55           ` Jan Beulich
  0 siblings, 1 reply; 8+ messages in thread
From: Andrew Cooper @ 2016-02-11 13:41 UTC (permalink / raw)
  To: Jan Beulich; +Cc: Xen-devel

On 11/02/16 12:52, Jan Beulich wrote:
>>>> On 11.02.16 at 13:12, <andrew.cooper3@citrix.com> wrote:
>> On 11/02/16 11:16, Jan Beulich wrote:
>>>>>> On 11.02.16 at 11:52, <andrew.cooper3@citrix.com> wrote:
>>>> --- a/xen/arch/x86/traps.c
>>>> +++ b/xen/arch/x86/traps.c
>>>> @@ -114,6 +114,56 @@ boolean_param("ler", opt_ler);
>>>>  #define stack_words_per_line 4
>>>>  #define ESP_BEFORE_EXCEPTION(regs) ((unsigned long *)regs->rsp)
>>>>  
>>>> +static void show_code(const struct cpu_user_regs *regs)
>>>> +{
>>>> +    unsigned char insns_before[8], insns_after[16];
>>>> +    unsigned int i, missing_before, missing_after;
>>>> +
>>>> +    if ( guest_mode(regs) )
>>>> +        return;
>>>> +
>>>> +    /*
>>>> +     * This dance with {insns,missing}_{before,after} is to ensure that, if
>>>> +     * %rip -8/+16 wraps around a bounday, we read a non-wrapped regs->rip
>>>> +     * pointer, and calculate which bytes were not read so they may be
>>>> +     * replaced with dashes in the printed output.
>>>> +     */
>>>> +    missing_before = __copy_from_user(
>>>> +        insns_before, (void __user *)regs->rip - 8, ARRAY_SIZE(insns_before));
>>>> +    missing_after = __copy_from_user(
>>>> +        insns_after, (void __user *)regs->rip, ARRAY_SIZE(insns_after));
>>> ... iirc __copy_from_user() doesn't range check the addresses.
>>> Also reading the leading bytes is done in kind of a strange way: It'll
>>> read initial bytes (farther away from RIP) and perhaps not read
>>> later ones (closer to RIP), albeit clearly the ones closer are of more
>>> interest. In the extreme case, where RIP is only a few bytes into a
>>> page following an unmapped one, no leading bytes would be printed
>>> at all despite some actually being readable.
>> I think in this specific case, it might be best to hand roll some asm
>> using rep movs and the direction flag, with manual fault handling.
> That's certainly an option.

It is turning out to be much nicer.

>
>>> Avoiding actual wrapping could be easily done by extending the
>>> guest_mode() check above to also range check RIP against the
>>> hypervisor image boundaries (post-boot this could even be limited
>>> further, but perhaps using the full XEN_VIRT_{START,END} range is
>>> the better route with xSplice in mind.
>> I would like, where possible, to avoid omitting the instruction stream
>> if Xen is outside of its expected boundaries.
> Which is because of ...? What useful information do you think can
> be gained from the actual instruction when the mere fact of being
> outside the boundaries is a bug?

Wherever %rip is pointing, the code under %rip is directly relevant to
the exact values of the registers and stack dump printed.

It will be obvious from the numeric value of %rip whether it is bad
(also, whether symbol information is found), and making it work for all
cases is easier than restricting to the Xen-only case.

~Andrew

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 2/2] x86/traps: Dump instruction stream in show_execution_state()
  2016-02-11 13:41         ` Andrew Cooper
@ 2016-02-11 13:55           ` Jan Beulich
  0 siblings, 0 replies; 8+ messages in thread
From: Jan Beulich @ 2016-02-11 13:55 UTC (permalink / raw)
  To: Andrew Cooper; +Cc: Xen-devel

>>> On 11.02.16 at 14:41, <andrew.cooper3@citrix.com> wrote:
> Wherever %rip is pointing, the code under %rip is directly relevant to
> the exact values of the registers and stack dump printed.
> 
> It will be obvious from the numeric value of %rip whether it is bad
> (also, whether symbol information is found), and making it work for all
> cases is easier than restricting to the Xen-only case.

Let's see (at the example of v3) whether this "easier" actually holds...

Jan

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v3 2/2] x86/traps: Dump instruction stream in show_execution_state()
  2016-02-11 10:52 ` [PATCH v2 2/2] x86/traps: Dump instruction stream in show_execution_state() Andrew Cooper
  2016-02-11 11:16   ` Jan Beulich
@ 2016-02-11 14:33   ` Andrew Cooper
  1 sibling, 0 replies; 8+ messages in thread
From: Andrew Cooper @ 2016-02-11 14:33 UTC (permalink / raw)
  To: Xen-devel; +Cc: Andrew Cooper, Jan Beulich

For first pass triage of crashes, it is useful to have the instruction
stream present, especially now that Xen binary patches itself.

A sample output now looks like:

(XEN) ----[ Xen-4.7-unstable  x86_64  debug=y  Not tainted ]----
(XEN) CPU:    0
(XEN) RIP:    e008:[<ffff82d0801607e4>] default_idle+0x76/0x7b
(XEN) RFLAGS: 0000000000000246   CONTEXT: hypervisor
(XEN) rax: ffff82d080331030   rbx: ffff83007fce8000   rcx: 0000000000000000
(XEN) rdx: 0000000000000000   rsi: ffff82d080331b98   rdi: 0000000000000000
(XEN) rbp: ffff83007fcefef0   rsp: ffff83007fcefef0   r8:  ffff83007faf8118
(XEN) r9:  00000009983e89fd   r10: 00000009983e89fd   r11: 0000000000000246
(XEN) r12: ffff83007fd61000   r13: 00000000ffffffff   r14: ffff83007fad9000
(XEN) r15: ffff83007fae3000   cr0: 000000008005003b   cr4: 00000000000026e0
(XEN) cr3: 000000007fc9b000   cr2: 00007f70976b3fed
(XEN) ds: 0000   es: 0000   fs: 0000   gs: 0000   ss: e010   cs: e008
(XEN) Xen code around <ffff82d0801607e4> (default_idle+0x76/0x7b):
(XEN)  83 3c 10 00 75 04 fb f4 <eb> 01 fb 5d c3 55 48 89 e5 3b 3d 0d 50 12 00 72
(XEN) Xen stack trace from rsp=ffff83007fcefef0:
(XEN)    ffff83007fceff10 ffff82d080160e08 ffff82d08012c40a ffff83007faf9000
(XEN)    ffff83007fcefdd8 ffffffff81a01fd8 ffff88002f07d4c0 ffffffff81a01fd8
(XEN)    0000000000000000 ffffffff81a01e58 ffffffff81a01fd8 0000000000000246
(XEN)    00000000ffff0052 0000000000000000 0000000000000000 0000000000000000
(XEN)    ffffffff810013aa 0000000000000001 00000000deadbeef 00000000deadbeef
(XEN)    0000010000000000 ffffffff810013aa 000000000000e033 0000000000000246
(XEN)    ffffffff81a01e40 000000000000e02b 0000000000000000 0000000000000000
(XEN)    0000000000000000 0000000000000000 0000000000000000 ffff83007faf9000
(XEN)    0000000000000000 0000000000000000
(XEN) Xen call trace:
(XEN)    [<ffff82d0801607e4>] default_idle+0x76/0x7b
(XEN)    [<ffff82d080160e08>] idle_loop+0x51/0x6e
(XEN)

A sample with a partial access looks like:

(XEN) Xen code around <ffff8300ac0fe002> (ffff8300ac0fe002) [fault on access]:
(XEN)  -- -- -- -- -- -- 00 00 <00> 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
---
CC: Jan Beulich <JBeulich@suse.com>

v3:
 * Read backwards from %rip, to get the instructions closer to %rip in the
   case that there is a fault somewhere on the access.  Use handrolled asm
   with custom fault handling.
v2:
 * Deal with %rip wrapping.  In such a case, insert dashes into printed line.
---
 xen/arch/x86/traps.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 69 insertions(+)

diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c
index ab7deee..26a5026 100644
--- a/xen/arch/x86/traps.c
+++ b/xen/arch/x86/traps.c
@@ -114,6 +114,74 @@ boolean_param("ler", opt_ler);
 #define stack_words_per_line 4
 #define ESP_BEFORE_EXCEPTION(regs) ((unsigned long *)regs->rsp)
 
+static void show_code(const struct cpu_user_regs *regs)
+{
+    unsigned char insns_before[8] = {}, insns_after[16] = {};
+    unsigned int i, tmp, missing_before, missing_after;
+
+    if ( guest_mode(regs) )
+        return;
+
+    stac();
+
+    /*
+     * Copy forward from regs->rip.  In the case of a fault, %ecx contains the
+     * number of bytes remaining to copy.
+     */
+    asm volatile ("1: rep movsb; 2:"
+                  _ASM_EXTABLE(1b, 2b)
+                  : "=&c" (missing_after),
+                    "=&D" (tmp), "=&S" (tmp)
+                  : "0" (ARRAY_SIZE(insns_after)),
+                    "1" (insns_after),
+                    "2" (regs->rip));
+
+    /*
+     * Copy backwards from regs->rip - 1.  In the case of a fault, %ecx
+     * contains the number of bytes remaining to copy.
+     */
+    asm volatile ("std;"
+                  "1: rep movsb;"
+                  "2: cld;"
+                  _ASM_EXTABLE(1b, 2b)
+                  : "=&c" (missing_before),
+                    "=&D" (tmp), "=&S" (tmp)
+                  : "0" (ARRAY_SIZE(insns_before)),
+                    "1" (insns_before + ARRAY_SIZE(insns_before)),
+                    "2" (regs->rip - 1));
+    clac();
+
+    printk("Xen code around <%p> (%ps)%s:\n",
+           _p(regs->rip), _p(regs->rip),
+           (missing_before || missing_after) ? " [fault on access]" : "");
+
+    /* Print bytes from insns_before[]. */
+    for ( i = 0; i < ARRAY_SIZE(insns_before); ++i )
+    {
+        if ( i < missing_before )
+            printk(" --");
+        else
+            printk(" %02x", insns_before[i]);
+    }
+
+    /* Print the byte under %rip. */
+    if ( missing_after != ARRAY_SIZE(insns_after) )
+        printk(" <%02x>", insns_after[0]);
+    else
+        printk(" <-->");
+
+    /* Print bytes from insns_after[]. */
+    for ( i = 1; i < ARRAY_SIZE(insns_after); ++i )
+    {
+        if ( i < (ARRAY_SIZE(insns_after) - missing_after) )
+            printk(" %02x", insns_after[i]);
+        else
+            printk(" --");
+    }
+
+    printk("\n");
+}
+
 static void show_guest_stack(struct vcpu *v, const struct cpu_user_regs *regs)
 {
     int i;
@@ -420,6 +488,7 @@ void show_execution_state(const struct cpu_user_regs *regs)
     unsigned long flags = console_lock_recursive_irqsave();
 
     show_registers(regs);
+    show_code(regs);
     show_stack(regs);
 
     console_unlock_recursive_irqrestore(flags);
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2016-02-11 14:33 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-02-11 10:52 [PATCH v2 1/2] x86/traps: Prevent interleaving of concurrent cpu state dumps Andrew Cooper
2016-02-11 10:52 ` [PATCH v2 2/2] x86/traps: Dump instruction stream in show_execution_state() Andrew Cooper
2016-02-11 11:16   ` Jan Beulich
2016-02-11 12:12     ` Andrew Cooper
2016-02-11 12:52       ` Jan Beulich
2016-02-11 13:41         ` Andrew Cooper
2016-02-11 13:55           ` Jan Beulich
2016-02-11 14:33   ` [PATCH v3 " Andrew Cooper

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.