@@ -4,6 +4,7 @@
#include <xen/perfc.h>
#include <xen/sort.h>
#include <xen/spinlock.h>
+#include <xen/xsplice.h>
#include <asm/uaccess.h>
#define EX_FIELD(ptr, field) ((unsigned long)&(ptr)->field + (ptr)->field)
@@ -18,7 +19,7 @@ static inline unsigned long ex_cont(const struct exception_table_entry *x)
return EX_FIELD(x, cont);
}
-static int __init cmp_ex(const void *a, const void *b)
+static int cmp_ex(const void *a, const void *b)
{
const struct exception_table_entry *l = a, *r = b;
unsigned long lip = ex_addr(l);
@@ -33,7 +34,7 @@ static int __init cmp_ex(const void *a, const void *b)
}
#ifndef swap_ex
-static void __init swap_ex(void *a, void *b, int size)
+static void swap_ex(void *a, void *b, int size)
{
struct exception_table_entry *l = a, *r = b, tmp;
long delta = b - a;
@@ -46,19 +47,23 @@ static void __init swap_ex(void *a, void *b, int size)
}
#endif
-void __init sort_exception_tables(void)
+void sort_exception_table(struct exception_table_entry *start,
+ struct exception_table_entry *stop)
{
- sort(__start___ex_table, __stop___ex_table - __start___ex_table,
- sizeof(struct exception_table_entry), cmp_ex, swap_ex);
- sort(__start___pre_ex_table,
- __stop___pre_ex_table - __start___pre_ex_table,
+ sort(start, stop - start,
sizeof(struct exception_table_entry), cmp_ex, swap_ex);
}
-static inline unsigned long
-search_one_table(const struct exception_table_entry *first,
- const struct exception_table_entry *last,
- unsigned long value)
+void __init sort_exception_tables(void)
+{
+ sort_exception_table(__start___ex_table, __stop___ex_table);
+ sort_exception_table(__start___pre_ex_table, __stop___pre_ex_table);
+}
+
+unsigned long
+search_one_extable(const struct exception_table_entry *first,
+ const struct exception_table_entry *last,
+ unsigned long value)
{
const struct exception_table_entry *mid;
long diff;
@@ -80,15 +85,18 @@ search_one_table(const struct exception_table_entry *first,
unsigned long
search_exception_table(unsigned long addr)
{
- return search_one_table(
- __start___ex_table, __stop___ex_table-1, addr);
+ if ( likely(is_kernel(addr)) )
+ return search_one_extable(
+ __start___ex_table, __stop___ex_table-1, addr);
+ else
+ return search_module_extables(addr);
}
unsigned long
search_pre_exception_table(struct cpu_user_regs *regs)
{
unsigned long addr = (unsigned long)regs->eip;
- unsigned long fixup = search_one_table(
+ unsigned long fixup = search_one_extable(
__start___pre_ex_table, __stop___pre_ex_table-1, addr);
if ( fixup )
{
@@ -47,6 +47,10 @@ struct payload {
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];
+#ifdef CONFIG_X86
+ struct exception_table_entry *start_ex_table;
+ struct exception_table_entry *stop_ex_table;
+#endif
char name[XEN_XSPLICE_NAME_SIZE + 1];/* Name of it. */
};
@@ -668,6 +672,20 @@ static int find_special_sections(struct payload *payload,
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);
}
+#ifdef CONFIG_X86
+ sec = xsplice_elf_sec_by_name(elf, ".ex_table");
+ if ( sec )
+ {
+ if ( ( !sec->sec->sh_size ) ||
+ ( sec->sec->sh_size % sizeof *sec->load_addr ) )
+ return -EINVAL;
+
+ payload->start_ex_table = (struct exception_table_entry *)sec->load_addr;
+ payload->stop_ex_table = (struct exception_table_entry *)(sec->load_addr + sec->sec->sh_size);
+
+ sort_exception_table(payload->start_ex_table, payload->stop_ex_table);
+ }
+#endif
return 0;
}
@@ -1029,6 +1047,32 @@ bool_t is_active_module_text(unsigned long addr)
return 0;
}
+#ifdef CONFIG_X86
+unsigned long search_module_extables(unsigned long addr)
+{
+ struct payload *data;
+ unsigned long ret;
+
+ /* No locking since this list is only ever changed during apply or revert
+ * context. */
+ list_for_each_entry ( data, &applied_list, applied_list )
+ {
+ if ( !data->start_ex_table )
+ continue;
+ if ( !((void *)addr >= data->payload_address &&
+ (void *)addr < (data->payload_address + data->core_text_size)))
+ continue;
+
+ ret = search_one_extable(data->start_ex_table, data->stop_ex_table - 1,
+ addr);
+ if ( ret )
+ return ret;
+ }
+
+ return 0;
+}
+#endif
+
static int __init xsplice_init(void)
{
register_keyhandler('x', xsplice_printall, "print xsplicing info", 1);
@@ -276,6 +276,11 @@ extern struct exception_table_entry __start___pre_ex_table[];
extern struct exception_table_entry __stop___pre_ex_table[];
extern unsigned long search_exception_table(unsigned long);
+extern unsigned long search_one_extable(const struct exception_table_entry *first,
+ const struct exception_table_entry *last,
+ unsigned long value);
extern void sort_exception_tables(void);
+extern void sort_exception_table(struct exception_table_entry *start,
+ struct exception_table_entry *stop);
#endif /* __X86_UACCESS_H__ */
@@ -29,6 +29,7 @@ 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);
+unsigned long search_module_extables(unsigned long addr);
#else
static inline void do_xsplice(void) { };
static inline struct bug_frame *xsplice_find_bug(const char *eip, int *id)
@@ -43,6 +44,10 @@ static inline bool_t is_active_module_text(unsigned long addr)
{
return 0;
}
+static inline unsigned long search_module_extables(unsigned long addr)
+{
+ return 0;
+}
#endif
/* Arch hooks */