diff mbox

[v2,11/13] xsplice: Add support for bug frames. (v2)

Message ID 1452808031-706-12-git-send-email-konrad.wilk@oracle.com (mailing list archive)
State New, archived
Headers show

Commit Message

Konrad Rzeszutek Wilk Jan. 14, 2016, 9:47 p.m. UTC
From: Ross Lagerwall <ross.lagerwall@citrix.com>

Add support for handling bug frames contained with xsplice modules. If a
trap occurs search either the kernel bug table or an applied payload's
bug table depending on the instruction pointer.

Signed-off-by: Ross Lagerwall <ross.lagerwall@citrix.com>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
---
v2:- s/module/payload/
   - add build time check in case amount of bug frames expands.
   - add define for the number of bug-frames.
---
 xen/arch/x86/traps.c      |  30 ++++++++-----
 xen/common/symbols.c      |   7 +++
 xen/common/xsplice.c      | 109 +++++++++++++++++++++++++++++++++++++++++-----
 xen/include/asm-arm/bug.h |   2 +
 xen/include/asm-x86/bug.h |   2 +
 xen/include/xen/kernel.h  |   1 +
 xen/include/xen/xsplice.h |  15 +++++++
 7 files changed, 145 insertions(+), 21 deletions(-)

Comments

Ross Lagerwall Jan. 19, 2016, 2:42 p.m. UTC | #1
On 01/14/2016 09:47 PM, Konrad Rzeszutek Wilk wrote:
> From: Ross Lagerwall <ross.lagerwall@citrix.com>
>
> Add support for handling bug frames contained with xsplice modules. If a
> trap occurs search either the kernel bug table or an applied payload's
> bug table depending on the instruction pointer.
>
> Signed-off-by: Ross Lagerwall <ross.lagerwall@citrix.com>
snip

> Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>

> diff --git a/xen/common/xsplice.c b/xen/common/xsplice.c
> index 5abeb28..02cb4a8 100644
> --- a/xen/common/xsplice.c
> +++ b/xen/common/xsplice.c
> @@ -43,7 +43,10 @@ struct payload {
>       struct list_head applied_list;       /* Linked to 'applied_list'. */
>       struct xsplice_patch_func *funcs;    /* The array of functions to patch. */
>       unsigned int nfuncs;                 /* Nr of functions to patch. */
> -
> +    size_t core_size;                    /* Only .text size. */
> +    size_t core_text_size;               /* Everything else - .data,.rodata, etc. */

These comments are the wrong way around.

> +    struct bug_frame *start_bug_frames[BUGFRAME_NR]; /* .bug.frame patching. */
> +    struct bug_frame *stop_bug_frames[BUGFRAME_NR];
>       char name[XEN_XSPLICE_NAME_SIZE + 1];/* Name of it. */
>   };
>
> @@ -544,26 +547,27 @@ static void free_payload_data(struct payload *payload)
>       payload->payload_pages = 0;
>   }
>
> -static void calc_section(struct xsplice_elf_sec *sec, size_t *core_size)
> +static void calc_section(struct xsplice_elf_sec *sec, size_t *size)
>   {
> -    size_t align_size = ROUNDUP(*core_size, sec->sec->sh_addralign);
> +    size_t align_size = ROUNDUP(*size, sec->sec->sh_addralign);
>       sec->sec->sh_entsize = align_size;
> -    *core_size = sec->sec->sh_size + align_size;
> +    *size = sec->sec->sh_size + align_size;
>   }
>
>   static int move_payload(struct payload *payload, struct xsplice_elf *elf)
>   {
>       uint8_t *buf;
>       unsigned int i;
> -    size_t core_size = 0;
> +    size_t size = 0;
>
>       /* Compute text regions */
>       for ( i = 0; i < elf->hdr->e_shnum; i++ )
>       {
>           if ( (elf->sec[i].sec->sh_flags & (SHF_ALLOC|SHF_EXECINSTR)) ==
>                (SHF_ALLOC|SHF_EXECINSTR) )
> -            calc_section(&elf->sec[i], &core_size);
> +            calc_section(&elf->sec[i], &size);
>       }
> +    payload->core_text_size = size;
>
>       /* Compute rw data */
>       for ( i = 0; i < elf->hdr->e_shnum; i++ )
> @@ -571,7 +575,7 @@ static int move_payload(struct payload *payload, struct xsplice_elf *elf)
>           if ( (elf->sec[i].sec->sh_flags & SHF_ALLOC) &&
>                !(elf->sec[i].sec->sh_flags & SHF_EXECINSTR) &&
>                (elf->sec[i].sec->sh_flags & SHF_WRITE) )
> -            calc_section(&elf->sec[i], &core_size);
> +            calc_section(&elf->sec[i], &size);
>       }
>
>       /* Compute ro data */
> @@ -580,16 +584,17 @@ static int move_payload(struct payload *payload, struct xsplice_elf *elf)
>           if ( (elf->sec[i].sec->sh_flags & SHF_ALLOC) &&
>                !(elf->sec[i].sec->sh_flags & SHF_EXECINSTR) &&
>                !(elf->sec[i].sec->sh_flags & SHF_WRITE) )
> -            calc_section(&elf->sec[i], &core_size);
> +            calc_section(&elf->sec[i], &size);
>       }
> +    payload->core_size = size;
>
> -    buf = alloc_payload(core_size);
> +    buf = alloc_payload(size);
>       if ( !buf ) {
>           printk(XENLOG_ERR "%s: Could not allocate memory for module\n",
>                  elf->name);
>           return -ENOMEM;
>       }
> -    memset(buf, 0, core_size);
> +    memset(buf, 0, size);
>
>       for ( i = 0; i < elf->hdr->e_shnum; i++ )
>       {
> @@ -604,7 +609,7 @@ static int move_payload(struct payload *payload, struct xsplice_elf *elf)
>       }
>
>       payload->payload_address = buf;
> -    payload->payload_pages = PFN_UP(core_size);
> +    payload->payload_pages = PFN_UP(size);

These renames should be folded into the originating patch (patch 8) or 
dropped.

>
>       return 0;
>   }
> @@ -647,6 +652,22 @@ static int find_special_sections(struct payload *payload,
>               if ( f->pad[j] )
>                   return -EINVAL;
>       }
> +    for ( i = 0; i < BUGFRAME_NR; i++ )
> +    {
> +        char str[14];
> +
> +        snprintf(str, sizeof str, ".bug_frames.%d", i);
> +        sec = xsplice_elf_sec_by_name(elf, str);
> +        if ( !sec )
> +            continue;
> +
> +        if ( ( !sec->sec->sh_size ) ||
> +             ( sec->sec->sh_size % sizeof (struct bug_frame) ) )
> +            return -EINVAL;
> +
> +        payload->start_bug_frames[i] = (struct bug_frame *)sec->load_addr;
> +        payload->stop_bug_frames[i] = (struct bug_frame *)(sec->load_addr + sec->sec->sh_size);
> +    }
>       return 0;
>   }
>
> @@ -942,6 +963,72 @@ void do_xsplice(void)
>       }
>   }
>
> +
> +/*
> + * Functions for handling special sections.
> + */
> +struct bug_frame *xsplice_find_bug(const char *eip, int *id)
> +{
> +    struct payload *data;
> +    struct bug_frame *bug;
> +    int i;
> +
> +    /* No locking since this list is only ever changed during apply or revert
> +     * context. */
> +    list_for_each_entry ( data, &applied_list, applied_list )
> +    {
> +        for (i = 0; i < 4; i++) {

BUGFRAME_NR

> +            if (!data->start_bug_frames[i])
> +                continue;
> +            if ( !((void *)eip >= data->payload_address &&
> +                   (void *)eip < (data->payload_address + data->core_text_size)))
> +                continue;
> +
> +            for ( bug = data->start_bug_frames[i]; bug != data->stop_bug_frames[i]; ++bug ) {
> +                if ( bug_loc(bug) == eip )
> +                {
> +                    *id = i;
> +                    return bug;
> +                }
> +            }
> +        }
> +    }
> +
> +    return NULL;
> +}
> +
diff mbox

Patch

diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c
index e105b95..6e80607 100644
--- a/xen/arch/x86/traps.c
+++ b/xen/arch/x86/traps.c
@@ -48,6 +48,7 @@ 
 #include <xen/kexec.h>
 #include <xen/trace.h>
 #include <xen/paging.h>
+#include <xen/xsplice.h>
 #include <xen/watchdog.h>
 #include <asm/system.h>
 #include <asm/io.h>
@@ -1080,20 +1081,29 @@  void do_invalid_op(struct cpu_user_regs *regs)
         return;
     }
 
-    if ( !is_active_kernel_text(regs->eip) ||
+    if ( !is_active_text(regs->eip) ||
          __copy_from_user(bug_insn, eip, sizeof(bug_insn)) ||
          memcmp(bug_insn, "\xf\xb", sizeof(bug_insn)) )
         goto die;
 
-    for ( bug = __start_bug_frames, id = 0; stop_frames[id]; ++bug )
+    if ( likely(is_active_kernel_text(regs->eip)) )
     {
-        while ( unlikely(bug == stop_frames[id]) )
-            ++id;
-        if ( bug_loc(bug) == eip )
-            break;
+        for ( bug = __start_bug_frames, id = 0; stop_frames[id]; ++bug )
+        {
+            while ( unlikely(bug == stop_frames[id]) )
+                ++id;
+            if ( bug_loc(bug) == eip )
+                break;
+        }
+        if ( !stop_frames[id] )
+            goto die;
+    }
+    else
+    {
+        bug = xsplice_find_bug(eip, &id);
+        if ( !bug )
+            goto die;
     }
-    if ( !stop_frames[id] )
-        goto die;
 
     eip += sizeof(bug_insn);
     if ( id == BUGFRAME_run_fn )
@@ -1107,7 +1117,7 @@  void do_invalid_op(struct cpu_user_regs *regs)
 
     /* WARN, BUG or ASSERT: decode the filename pointer and line number. */
     filename = bug_ptr(bug);
-    if ( !is_kernel(filename) )
+    if ( !is_kernel(filename) && !is_module(filename) )
         goto die;
     fixup = strlen(filename);
     if ( fixup > 50 )
@@ -1134,7 +1144,7 @@  void do_invalid_op(struct cpu_user_regs *regs)
     case BUGFRAME_assert:
         /* ASSERT: decode the predicate string pointer. */
         predicate = bug_msg(bug);
-        if ( !is_kernel(predicate) )
+        if ( !is_kernel(predicate) && !is_module(predicate) )
             predicate = "<unknown>";
 
         printk("Assertion '%s' failed at %s%s:%d\n",
diff --git a/xen/common/symbols.c b/xen/common/symbols.c
index a59c59d..bf5623f 100644
--- a/xen/common/symbols.c
+++ b/xen/common/symbols.c
@@ -17,6 +17,7 @@ 
 #include <xen/lib.h>
 #include <xen/string.h>
 #include <xen/spinlock.h>
+#include <xen/xsplice.h>
 #include <public/platform.h>
 #include <xen/guest_access.h>
 
@@ -101,6 +102,12 @@  bool_t is_active_kernel_text(unsigned long addr)
             (system_state < SYS_STATE_active && is_kernel_inittext(addr)));
 }
 
+bool_t is_active_text(unsigned long addr)
+{
+    return is_active_kernel_text(addr) ||
+           is_active_module_text(addr);
+}
+
 const char *symbols_lookup(unsigned long addr,
                            unsigned long *symbolsize,
                            unsigned long *offset,
diff --git a/xen/common/xsplice.c b/xen/common/xsplice.c
index 5abeb28..02cb4a8 100644
--- a/xen/common/xsplice.c
+++ b/xen/common/xsplice.c
@@ -43,7 +43,10 @@  struct payload {
     struct list_head applied_list;       /* Linked to 'applied_list'. */
     struct xsplice_patch_func *funcs;    /* The array of functions to patch. */
     unsigned int nfuncs;                 /* Nr of functions to patch. */
-
+    size_t core_size;                    /* Only .text size. */
+    size_t core_text_size;               /* Everything else - .data,.rodata, etc. */
+    struct bug_frame *start_bug_frames[BUGFRAME_NR]; /* .bug.frame patching. */
+    struct bug_frame *stop_bug_frames[BUGFRAME_NR];
     char name[XEN_XSPLICE_NAME_SIZE + 1];/* Name of it. */
 };
 
@@ -544,26 +547,27 @@  static void free_payload_data(struct payload *payload)
     payload->payload_pages = 0;
 }
 
-static void calc_section(struct xsplice_elf_sec *sec, size_t *core_size)
+static void calc_section(struct xsplice_elf_sec *sec, size_t *size)
 {
-    size_t align_size = ROUNDUP(*core_size, sec->sec->sh_addralign);
+    size_t align_size = ROUNDUP(*size, sec->sec->sh_addralign);
     sec->sec->sh_entsize = align_size;
-    *core_size = sec->sec->sh_size + align_size;
+    *size = sec->sec->sh_size + align_size;
 }
 
 static int move_payload(struct payload *payload, struct xsplice_elf *elf)
 {
     uint8_t *buf;
     unsigned int i;
-    size_t core_size = 0;
+    size_t size = 0;
 
     /* Compute text regions */
     for ( i = 0; i < elf->hdr->e_shnum; i++ )
     {
         if ( (elf->sec[i].sec->sh_flags & (SHF_ALLOC|SHF_EXECINSTR)) ==
              (SHF_ALLOC|SHF_EXECINSTR) )
-            calc_section(&elf->sec[i], &core_size);
+            calc_section(&elf->sec[i], &size);
     }
+    payload->core_text_size = size;
 
     /* Compute rw data */
     for ( i = 0; i < elf->hdr->e_shnum; i++ )
@@ -571,7 +575,7 @@  static int move_payload(struct payload *payload, struct xsplice_elf *elf)
         if ( (elf->sec[i].sec->sh_flags & SHF_ALLOC) &&
              !(elf->sec[i].sec->sh_flags & SHF_EXECINSTR) &&
              (elf->sec[i].sec->sh_flags & SHF_WRITE) )
-            calc_section(&elf->sec[i], &core_size);
+            calc_section(&elf->sec[i], &size);
     }
 
     /* Compute ro data */
@@ -580,16 +584,17 @@  static int move_payload(struct payload *payload, struct xsplice_elf *elf)
         if ( (elf->sec[i].sec->sh_flags & SHF_ALLOC) &&
              !(elf->sec[i].sec->sh_flags & SHF_EXECINSTR) &&
              !(elf->sec[i].sec->sh_flags & SHF_WRITE) )
-            calc_section(&elf->sec[i], &core_size);
+            calc_section(&elf->sec[i], &size);
     }
+    payload->core_size = size;
 
-    buf = alloc_payload(core_size);
+    buf = alloc_payload(size);
     if ( !buf ) {
         printk(XENLOG_ERR "%s: Could not allocate memory for module\n",
                elf->name);
         return -ENOMEM;
     }
-    memset(buf, 0, core_size);
+    memset(buf, 0, size);
 
     for ( i = 0; i < elf->hdr->e_shnum; i++ )
     {
@@ -604,7 +609,7 @@  static int move_payload(struct payload *payload, struct xsplice_elf *elf)
     }
 
     payload->payload_address = buf;
-    payload->payload_pages = PFN_UP(core_size);
+    payload->payload_pages = PFN_UP(size);
 
     return 0;
 }
@@ -647,6 +652,22 @@  static int find_special_sections(struct payload *payload,
             if ( f->pad[j] )
                 return -EINVAL;
     }
+    for ( i = 0; i < BUGFRAME_NR; i++ )
+    {
+        char str[14];
+
+        snprintf(str, sizeof str, ".bug_frames.%d", i);
+        sec = xsplice_elf_sec_by_name(elf, str);
+        if ( !sec )
+            continue;
+
+        if ( ( !sec->sec->sh_size ) ||
+             ( sec->sec->sh_size % sizeof (struct bug_frame) ) )
+            return -EINVAL;
+
+        payload->start_bug_frames[i] = (struct bug_frame *)sec->load_addr;
+        payload->stop_bug_frames[i] = (struct bug_frame *)(sec->load_addr + sec->sec->sh_size);
+    }
     return 0;
 }
 
@@ -942,6 +963,72 @@  void do_xsplice(void)
     }
 }
 
+
+/*
+ * Functions for handling special sections.
+ */
+struct bug_frame *xsplice_find_bug(const char *eip, int *id)
+{
+    struct payload *data;
+    struct bug_frame *bug;
+    int i;
+
+    /* No locking since this list is only ever changed during apply or revert
+     * context. */
+    list_for_each_entry ( data, &applied_list, applied_list )
+    {
+        for (i = 0; i < 4; i++) {
+            if (!data->start_bug_frames[i])
+                continue;
+            if ( !((void *)eip >= data->payload_address &&
+                   (void *)eip < (data->payload_address + data->core_text_size)))
+                continue;
+
+            for ( bug = data->start_bug_frames[i]; bug != data->stop_bug_frames[i]; ++bug ) {
+                if ( bug_loc(bug) == eip )
+                {
+                    *id = i;
+                    return bug;
+                }
+            }
+        }
+    }
+
+    return NULL;
+}
+
+bool_t is_module(const void *ptr)
+{
+    struct payload *data;
+
+    /* No locking since this list is only ever changed during apply or revert
+     * context. */
+    list_for_each_entry ( data, &applied_list, applied_list )
+    {
+        if ( ptr >= data->payload_address &&
+             ptr < (data->payload_address + data->core_size))
+            return 1;
+    }
+
+    return 0;
+}
+
+bool_t is_active_module_text(unsigned long addr)
+{
+    struct payload *data;
+
+    /* No locking since this list is only ever changed during apply or revert
+     * context. */
+    list_for_each_entry ( data, &applied_list, applied_list )
+    {
+        if ( (void *)addr >= data->payload_address &&
+             (void *)addr < (data->payload_address + data->core_text_size))
+            return 1;
+    }
+
+    return 0;
+}
+
 static int __init xsplice_init(void)
 {
     register_keyhandler('x', xsplice_printall, "print xsplicing info", 1);
diff --git a/xen/include/asm-arm/bug.h b/xen/include/asm-arm/bug.h
index ab9e811..4df6b2a 100644
--- a/xen/include/asm-arm/bug.h
+++ b/xen/include/asm-arm/bug.h
@@ -31,6 +31,7 @@  struct bug_frame {
 #define BUGFRAME_warn   0
 #define BUGFRAME_bug    1
 #define BUGFRAME_assert 2
+#define BUGFRAME_NR     3
 
 /* Many versions of GCC doesn't support the asm %c parameter which would
  * be preferable to this unpleasantness. We use mergeable string
@@ -39,6 +40,7 @@  struct bug_frame {
  */
 #define BUG_FRAME(type, line, file, has_msg, msg) do {                      \
     BUILD_BUG_ON((line) >> 16);                                             \
+    BUILD_BUG_ON(type >= BUGFRAME_NR);                                      \
     asm ("1:"BUG_INSTR"\n"                                                  \
          ".pushsection .rodata.str, \"aMS\", %progbits, 1\n"                \
          "2:\t.asciz " __stringify(file) "\n"                               \
diff --git a/xen/include/asm-x86/bug.h b/xen/include/asm-x86/bug.h
index e868e85..5443191 100644
--- a/xen/include/asm-x86/bug.h
+++ b/xen/include/asm-x86/bug.h
@@ -9,6 +9,7 @@ 
 #define BUGFRAME_warn   1
 #define BUGFRAME_bug    2
 #define BUGFRAME_assert 3
+#define BUGFRAME_NR     4
 
 #ifndef __ASSEMBLY__
 
@@ -51,6 +52,7 @@  struct bug_frame {
 
 #define BUG_FRAME(type, line, ptr, second_frame, msg) do {                   \
     BUILD_BUG_ON((line) >> (BUG_LINE_LO_WIDTH + BUG_LINE_HI_WIDTH));         \
+    BUILD_BUG_ON((type) >= (BUGFRAME_NR));                                   \
     asm volatile ( _ASM_BUGFRAME_TEXT(second_frame)                          \
                    :: _ASM_BUGFRAME_INFO(type, line, ptr, msg) );            \
 } while (0)
diff --git a/xen/include/xen/kernel.h b/xen/include/xen/kernel.h
index 548b64d..df57754 100644
--- a/xen/include/xen/kernel.h
+++ b/xen/include/xen/kernel.h
@@ -99,6 +99,7 @@  extern enum system_state {
 } system_state;
 
 bool_t is_active_kernel_text(unsigned long addr);
+bool_t is_active_text(unsigned long addr);
 
 #endif /* _LINUX_KERNEL_H */
 
diff --git a/xen/include/xen/xsplice.h b/xen/include/xen/xsplice.h
index 61a9ec6..41b738a 100644
--- a/xen/include/xen/xsplice.h
+++ b/xen/include/xen/xsplice.h
@@ -26,8 +26,23 @@  int xsplice_control(struct xen_sysctl_xsplice_op *);
 
 #ifdef CONFIG_XSPLICE
 void do_xsplice(void);
+struct bug_frame *xsplice_find_bug(const char *eip, int *id);
+bool_t is_module(const void *addr);
+bool_t is_active_module_text(unsigned long addr);
 #else
 static inline void do_xsplice(void) { };
+static inline struct bug_frame *xsplice_find_bug(const char *eip, int *id)
+{
+	return NULL;
+}
+static inline bool_t is_module(const void *addr)
+{
+	return 0;
+}
+static inline bool_t is_active_module_text(unsigned long addr)
+{
+	return 0;
+}
 #endif
 
 /* Arch hooks */