@@ -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",
@@ -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,
@@ -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);
@@ -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" \
@@ -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)
@@ -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 */
@@ -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 */