diff options
Diffstat (limited to 'runtime')
-rw-r--r-- | runtime/print.c | 28 | ||||
-rw-r--r-- | runtime/runtime.h | 14 | ||||
-rw-r--r-- | runtime/sym.c | 27 | ||||
-rw-r--r-- | runtime/sym.h | 1 | ||||
-rw-r--r-- | runtime/syscall.h | 25 | ||||
-rw-r--r-- | runtime/unwind.c | 4 | ||||
-rw-r--r-- | runtime/unwind/unwind.h | 4 | ||||
-rw-r--r-- | runtime/uprobes/uprobes.c | 34 | ||||
-rw-r--r-- | runtime/uprobes/uprobes.h | 6 | ||||
-rw-r--r-- | runtime/uprobes/uprobes_i386.c | 3 | ||||
-rw-r--r-- | runtime/uprobes/uprobes_x86.c | 9 | ||||
-rw-r--r-- | runtime/uprobes/uprobes_x86_64.c | 7 | ||||
-rw-r--r-- | runtime/uprobes2/uprobes.c | 43 | ||||
-rw-r--r-- | runtime/uprobes2/uprobes.h | 6 | ||||
-rw-r--r-- | runtime/uprobes2/uprobes_x86.c | 9 | ||||
-rw-r--r-- | runtime/vsprintf.c | 355 |
16 files changed, 479 insertions, 96 deletions
diff --git a/runtime/print.c b/runtime/print.c index 2c84d3c9..964a73c2 100644 --- a/runtime/print.c +++ b/runtime/print.c @@ -13,8 +13,8 @@ #include "string.h" -#include "vsprintf.c" #include "transport/transport.c" +#include "vsprintf.c" /** @file print.c * Printing Functions. @@ -173,34 +173,10 @@ static void _stp_print_binary (int num, ...) */ static void _stp_printf (const char *fmt, ...) { - int num; va_list args; - _stp_pbuf *pb = per_cpu_ptr(Stp_pbuf, smp_processor_id()); - char *buf = pb->buf + pb->len; - int size = STP_BUFFER_SIZE - pb->len; - va_start(args, fmt); - num = _stp_vsnprintf(buf, size, fmt, args); + _stp_vsnprintf(NULL, 0, fmt, args); va_end(args); - if (unlikely(num >= size)) { - /* overflowed the buffer */ - if (pb->len == 0) { - /* A single print request exceeded the buffer size. */ - /* Should not be possible with Systemtap-generated code. */ - pb->len = STP_BUFFER_SIZE; - _stp_print_flush(); - num = 0; - } else { - /* Need more space. Flush the previous contents */ - _stp_print_flush(); - - /* try again */ - va_start(args, fmt); - num = _stp_vsnprintf(pb->buf, STP_BUFFER_SIZE, fmt, args); - va_end(args); - } - } - pb->len += num; } /** Write a string into the print buffer. diff --git a/runtime/runtime.h b/runtime/runtime.h index 0a656b78..c2e927cc 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -66,6 +66,13 @@ static struct #define MAXTRACE 20 #endif +/* dwarf unwinder only tested so far on i386 and x86_64. */ +#if (defined(__i386__) || defined(__x86_64__)) +#ifndef STP_USE_DWARF_UNWINDER +#define STP_USE_DWARF_UNWINDER +#endif +#endif + #ifdef CONFIG_FRAME_POINTER /* Just because frame pointers are available does not mean we can trust them. */ #ifndef STP_USE_DWARF_UNWINDER @@ -73,13 +80,6 @@ static struct #endif #endif -/* dwarf unwinder only tested so far on i386 and x86_64, - but globally disabled for now */ -#if 0 -// !defined(STP_USE_FRAME_BUFFER) && (defined(__i386__) || defined(__x86_64__)) -#define STP_USE_DWARF_UNWINDER -#endif - #include "alloc.c" #include "print.c" #include "string.c" diff --git a/runtime/sym.c b/runtime/sym.c index a2cdd0ff..f6f97ac2 100644 --- a/runtime/sym.c +++ b/runtime/sym.c @@ -136,9 +136,7 @@ static struct _stp_module *_stp_mod_sec_lookup(unsigned long addr, struct _stp_section **sec) { void *user = NULL; - struct _stp_module *m = NULL; unsigned midx = 0; - unsigned long closest_section_offset = ~0; // Try vma matching first if task given. if (task) @@ -149,8 +147,9 @@ static struct _stp_module *_stp_mod_sec_lookup(unsigned long addr, NULL, &user) == 0) if (user != NULL) { - m = (struct _stp_module *)user; - *sec = &m->sections[0]; // XXX check actual section and relocate + struct _stp_module *m = (struct _stp_module *)user; + if (sec) + *sec = &m->sections[0]; // XXX check actual section and relocate dbug_sym(1, "found section %s in module %s at 0x%lx\n", m->sections[0].name, m->name, vm_start); if (strcmp(".dynamic", m->sections[0].name) == 0) @@ -164,21 +163,19 @@ static struct _stp_module *_stp_mod_sec_lookup(unsigned long addr, unsigned secidx; for (secidx = 0; secidx < _stp_modules[midx]->num_sections; secidx++) { - unsigned long this_section_addr; - unsigned long this_section_offset; - this_section_addr = _stp_modules[midx]->sections[secidx].addr; - if (addr < this_section_addr) continue; - this_section_offset = addr - this_section_addr; - if (this_section_offset < closest_section_offset) - { - closest_section_offset = this_section_offset; - m = _stp_modules[midx]; + unsigned long sec_addr; + unsigned long sec_size; + sec_addr = _stp_modules[midx]->sections[secidx].addr; + sec_size = _stp_modules[midx]->sections[secidx].size; + if (addr >= sec_addr && addr < sec_addr + sec_size) + { if (sec) - *sec = & m->sections[secidx]; + *sec = & _stp_modules[midx]->sections[secidx]; + return _stp_modules[midx]; } } } - return m; + return NULL; } diff --git a/runtime/sym.h b/runtime/sym.h index 586b10ca..80c334fb 100644 --- a/runtime/sym.h +++ b/runtime/sym.h @@ -18,6 +18,7 @@ struct _stp_symbol { struct _stp_section { const char *name; unsigned long addr; /* XXX: belongs in per-address-space tables */ + unsigned long size; /* length of the address space module covers. */ struct _stp_symbol *symbols; /* ordered by address */ unsigned num_symbols; }; diff --git a/runtime/syscall.h b/runtime/syscall.h index 6d22ba83..5e538389 100644 --- a/runtime/syscall.h +++ b/runtime/syscall.h @@ -124,7 +124,7 @@ syscall_get_nr(struct task_struct *task, struct pt_regs *regs) static inline long syscall_get_nr(struct task_struct *task, struct pt_regs *regs) { - return regs->r15; + return regs->r15; } #endif @@ -304,6 +304,17 @@ syscall_get_arguments(struct task_struct *task, struct pt_regs *regs, _stp_error("invalid syscall arg request"); return; } +#ifdef CONFIG_PPC64 + if (test_tsk_thread_flag(task, TIF_32BIT)) { + /* + * Zero-extend 32-bit argument values. The high bits are + * garbage ignored by the actual syscall dispatch. + */ + while (n-- > 0) + args[n] = (u32) regs->gpr[3 + i + n]; + return; + } +#endif memcpy(args, ®s->gpr[3 + i], n * sizeof(args[0])); } #endif @@ -324,22 +335,22 @@ __ia64_syscall_get_arguments(struct task_struct *task, struct pt_regs *regs, switch (i) { case 0: if (!n--) break; - *args++ = *__ia64_fetch_register(i + 32, regs, cache); + *args++ = ia64_fetch_register(32, regs, cache); case 1: if (!n--) break; - *args++ = *__ia64_fetch_register(i + 33, regs, cache); + *args++ = ia64_fetch_register(33, regs, cache); case 2: if (!n--) break; - *args++ = *__ia64_fetch_register(i + 34, regs, cache); + *args++ = ia64_fetch_register(34, regs, cache); case 3: if (!n--) break; - *args++ = *__ia64_fetch_register(i + 35, regs, cache); + *args++ = ia64_fetch_register(35, regs, cache); case 4: if (!n--) break; - *args++ = *__ia64_fetch_register(i + 36, regs, cache); + *args++ = ia64_fetch_register(36, regs, cache); case 5: if (!n--) break; - *args++ = *__ia64_fetch_register(i + 37, regs, cache); + *args++ = ia64_fetch_register(37, regs, cache); } } #endif diff --git a/runtime/unwind.c b/runtime/unwind.c index 9c704e28..41af72a7 100644 --- a/runtime/unwind.c +++ b/runtime/unwind.c @@ -345,7 +345,7 @@ static int processCFI(const u8 *start, const u8 *end, unsigned long targetLoc, s state->label = NULL; return 1; } - if (state->stackDepth >= MAX_STACK_DEPTH) + if (state->stackDepth >= STP_MAX_STACK_DEPTH) return 0; state->stack[state->stackDepth++] = ptr.p8; break; @@ -581,7 +581,7 @@ static int unwind(struct unwind_frame_info *frame) if (UNW_PC(frame) == 0) return -EINVAL; - m = _stp_mod_sec_lookup (pc, &s); + m = _stp_mod_sec_lookup (pc, current, &s); if (unlikely(m == NULL)) { dbug_unwind(1, "No module found for pc=%lx", pc); return -EINVAL; diff --git a/runtime/unwind/unwind.h b/runtime/unwind/unwind.h index 78a4bfef..3b6d0de0 100644 --- a/runtime/unwind/unwind.h +++ b/runtime/unwind/unwind.h @@ -23,7 +23,7 @@ #error "Unsupported dwarf unwind architecture" #endif -#define MAX_STACK_DEPTH 8 +#define STP_MAX_STACK_DEPTH 8 #ifndef BUILD_BUG_ON_ZERO #define BUILD_BUG_ON_ZERO(e) (sizeof(char[1 - 2 * !!(e)]) - 1) @@ -135,7 +135,7 @@ struct unwind_state { unsigned stackDepth:8; unsigned version:8; const u8 *label; - const u8 *stack[MAX_STACK_DEPTH]; + const u8 *stack[STP_MAX_STACK_DEPTH]; }; static const struct cfa badCFA = { ARRAY_SIZE(reg_info), 1 }; diff --git a/runtime/uprobes/uprobes.c b/runtime/uprobes/uprobes.c index 9dfb82b9..27e923b8 100644 --- a/runtime/uprobes/uprobes.c +++ b/runtime/uprobes/uprobes.c @@ -1049,8 +1049,7 @@ fail_tsk: } EXPORT_SYMBOL_GPL(register_uprobe); -/* See Documentation/uprobes.txt. */ -void unregister_uprobe(struct uprobe *u) +void __unregister_uprobe(struct uprobe *u, bool remove_bkpt) { struct task_struct *p; struct uprobe_process *uproc; @@ -1104,10 +1103,13 @@ void unregister_uprobe(struct uprobe *u) if (!list_empty(&ppt->uprobe_list)) goto done; - /* - * The last uprobe at ppt's probepoint is being unregistered. - * Queue the breakpoint for removal. - */ + /* The last uprobe at ppt's probepoint is being unregistered. */ + if (!remove_bkpt) { + uprobe_free_probept(ppt); + goto done; + } + + /* Queue the breakpoint for removal. */ ppt->state = UPROBE_REMOVING; list_add_tail(&ppt->pd_node, &uproc->pending_uprobes); @@ -1132,8 +1134,20 @@ done: up_write(&uproc->rwsem); uprobe_put_process(uproc); } + +/* See Documentation/uprobes.txt. */ +void unregister_uprobe(struct uprobe *u) +{ + __unregister_uprobe(u, true); +} EXPORT_SYMBOL_GPL(unregister_uprobe); +void unmap_uprobe(struct uprobe *u) +{ + __unregister_uprobe(u, false); +} +EXPORT_SYMBOL_GPL(unmap_uprobe); + /* Find a surviving thread in uproc. Runs with uproc->rwsem locked. */ static struct task_struct *find_surviving_thread(struct uprobe_process *uproc) { @@ -2540,6 +2554,14 @@ void unregister_uretprobe(struct uretprobe *rp) } EXPORT_SYMBOL_GPL(unregister_uretprobe); +void unmap_uretprobe(struct uretprobe *rp) +{ + if (!rp) + return; + unmap_uprobe(&rp->u); +} +EXPORT_SYMBOL_GPL(unmap_uretprobe); + /* * uproc->ssol_area has been successfully set up. Establish the * uretprobe trampoline in slot 0. diff --git a/runtime/uprobes/uprobes.h b/runtime/uprobes/uprobes.h index 0266cb7d..d542420d 100644 --- a/runtime/uprobes/uprobes.h +++ b/runtime/uprobes/uprobes.h @@ -35,6 +35,9 @@ #include <linux/types.h> #include <linux/list.h> +/* Version 2 includes unmap_u[ret]probe(). */ +#define UPROBES_API_VERSION 2 + struct pt_regs; enum uprobe_type { @@ -89,6 +92,9 @@ extern void unregister_uprobe(struct uprobe *u); /* For runtime, assume uprobes support includes uretprobes. */ extern int register_uretprobe(struct uretprobe *rp); extern void unregister_uretprobe(struct uretprobe *rp); +/* For PRs 9940, 6852... */ +extern void unmap_uprobe(struct uprobe *u); +extern void unmap_uretprobe(struct uretprobe *rp); #ifdef UPROBES_IMPLEMENTATION diff --git a/runtime/uprobes/uprobes_i386.c b/runtime/uprobes/uprobes_i386.c index ffa088ed..c43f87bf 100644 --- a/runtime/uprobes/uprobes_i386.c +++ b/runtime/uprobes/uprobes_i386.c @@ -44,7 +44,7 @@ W(0x60, 1,1,1,0,1,1,0,0,1,1,1,1,0,0,0,0)| /* 60 */ W(0x70, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), /* 70 */ W(0x80, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 80 */ - W(0x90, 1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1), /* 90 */ + W(0x90, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), /* 90 */ W(0xa0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* a0 */ W(0xb0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), /* b0 */ W(0xc0, 1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0)| /* c0 */ @@ -114,7 +114,6 @@ * 26, 2e, 36, 3e, - es:, cs:, ss:, ds: segment prefixes -- * but 64 and 65 (fs: and gs:) seems to be used, so we support them. * 67 - addr16 prefix - * 9b - wait/fwait * ce - into * f0 - lock prefix * f2, f3 - repnz, repz prefixes diff --git a/runtime/uprobes/uprobes_x86.c b/runtime/uprobes/uprobes_x86.c index e3bdf8ff..404c9518 100644 --- a/runtime/uprobes/uprobes_x86.c +++ b/runtime/uprobes/uprobes_x86.c @@ -45,8 +45,8 @@ static const unsigned long long good_insns_64[256 / 64] = { W(0x50, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 50 */ W(0x60, 0,0,0,1,1,1,0,0,1,1,1,1,0,0,0,0)| /* 60 */ W(0x70, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), /* 70 */ - W(0x80, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 80 */ - W(0x90, 1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1)| /* 90 */ + W(0x80, 1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 80 */ + W(0x90, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 90 */ W(0xa0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* a0 */ W(0xb0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), /* b0 */ W(0xc0, 1,1,1,1,0,0,1,1,1,1,1,1,0,0,0,0)| /* c0 */ @@ -71,7 +71,7 @@ static const unsigned long long good_insns_32[256 / 64] = { W(0x60, 1,1,1,0,1,1,0,0,1,1,1,1,0,0,0,0)| /* 60 */ W(0x70, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), /* 70 */ W(0x80, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 80 */ - W(0x90, 1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1)| /* 90 */ + W(0x90, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 90 */ W(0xa0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* a0 */ W(0xb0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), /* b0 */ W(0xc0, 1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0)| /* c0 */ @@ -119,7 +119,7 @@ static const unsigned long long good_2byte_insns[256 / 64] = { * 0f - lar, lsl, syscall, clts, sysret, sysenter, sysexit, invd, wbinvd, ud2 * * invalid opcodes in 64-bit mode: - * 06, 0e, 16, 1e, 27, 2f, 37, 3f, 60-62, c4-c5, d4-d5 + * 06, 0e, 16, 1e, 27, 2f, 37, 3f, 60-62, 82, c4-c5, d4-d5 * * 63 - we support this opcode in x86_64 but not in i386. * opcodes we may need to refine support for: @@ -141,7 +141,6 @@ static const unsigned long long good_2byte_insns[256 / 64] = { * 26, 2e, 36, 3e - es:, cs:, ss:, ds: segment prefixes -- * but 64 and 65 (fs: and gs:) seems to be used, so we support them. * 67 - addr16 prefix - * 9b - wait/fwait * ce - into * f0 - lock prefix */ diff --git a/runtime/uprobes/uprobes_x86_64.c b/runtime/uprobes/uprobes_x86_64.c index 8cf36623..56ebe2e1 100644 --- a/runtime/uprobes/uprobes_x86_64.c +++ b/runtime/uprobes/uprobes_x86_64.c @@ -45,8 +45,8 @@ static const unsigned long good_insns_64[256 / 64] = { W(0x50, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 50 */ W(0x60, 0,0,0,1,1,1,0,0,1,1,1,1,0,0,0,0)| /* 60 */ W(0x70, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), /* 70 */ - W(0x80, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 80 */ - W(0x90, 1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1)| /* 90 */ + W(0x80, 1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 80 */ + W(0x90, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 90 */ W(0xa0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* a0 */ W(0xb0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), /* b0 */ W(0xc0, 1,1,1,1,0,0,1,1,1,1,1,1,0,0,0,0)| /* c0 */ @@ -71,7 +71,7 @@ static const unsigned long good_insns_32[256 / 64] = { W(0x60, 1,1,1,0,1,1,0,0,1,1,1,1,0,0,0,0)| /* 60 */ W(0x70, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), /* 70 */ W(0x80, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 80 */ - W(0x90, 1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1)| /* 90 */ + W(0x90, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 90 */ W(0xa0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* a0 */ W(0xb0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), /* b0 */ W(0xc0, 1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0)| /* c0 */ @@ -141,7 +141,6 @@ static const unsigned long good_2byte_insns[256 / 64] = { * 26, 2e, 36, 3e - es:, cs:, ss:, ds: segment prefixes -- * but 64 and 65 (fs: and gs:) seems to be used, so we support them. * 67 - addr16 prefix - * 9b - wait/fwait * ce - into * f0 - lock prefix */ diff --git a/runtime/uprobes2/uprobes.c b/runtime/uprobes2/uprobes.c index a0e9f2fe..9ea05349 100644 --- a/runtime/uprobes2/uprobes.c +++ b/runtime/uprobes2/uprobes.c @@ -955,10 +955,15 @@ static int defer_registration(struct uprobe *u, int regflag, */ static struct pid *uprobe_get_tg_leader(pid_t p) { - struct pid *pid; + struct pid *pid = NULL; rcu_read_lock(); - pid = find_vpid(p); + /* + * We need this check because unmap_u[ret]probe() can be called + * from a report_death callback, where current->proxy is NULL. + */ + if (current->nsproxy) + pid = find_vpid(p); if (pid) { struct task_struct *t = pid_task(pid, PIDTYPE_PID); if (t) @@ -1138,8 +1143,7 @@ fail_tsk: } EXPORT_SYMBOL_GPL(register_uprobe); -/* See Documentation/uprobes.txt. */ -void unregister_uprobe(struct uprobe *u) +void __unregister_uprobe(struct uprobe *u, bool remove_bkpt) { struct pid *p; struct uprobe_process *uproc; @@ -1193,10 +1197,13 @@ void unregister_uprobe(struct uprobe *u) if (!list_empty(&ppt->uprobe_list)) goto done; - /* - * The last uprobe at ppt's probepoint is being unregistered. - * Queue the breakpoint for removal. - */ + /* The last uprobe at ppt's probepoint is being unregistered. */ + if (!remove_bkpt) { + uprobe_free_probept(ppt); + goto done; + } + + /* Queue the breakpoint for removal. */ ppt->state = UPROBE_REMOVING; list_add_tail(&ppt->pd_node, &uproc->pending_uprobes); @@ -1221,8 +1228,20 @@ done: up_write(&uproc->rwsem); uprobe_put_process(uproc, false); } + +/* See Documentation/uprobes.txt. */ +void unregister_uprobe(struct uprobe *u) +{ + __unregister_uprobe(u, true); +} EXPORT_SYMBOL_GPL(unregister_uprobe); +void unmap_uprobe(struct uprobe *u) +{ + __unregister_uprobe(u, false); +} +EXPORT_SYMBOL_GPL(unmap_uprobe); + /* Find a surviving thread in uproc. Runs with uproc->rwsem locked. */ static struct task_struct *find_surviving_thread(struct uprobe_process *uproc) { @@ -2718,6 +2737,14 @@ void unregister_uretprobe(struct uretprobe *rp) } EXPORT_SYMBOL_GPL(unregister_uretprobe); +void unmap_uretprobe(struct uretprobe *rp) +{ + if (!rp) + return; + unmap_uprobe(&rp->u); +} +EXPORT_SYMBOL_GPL(unmap_uretprobe); + /* * uproc->ssol_area has been successfully set up. Establish the * uretprobe trampoline in the next available slot following the diff --git a/runtime/uprobes2/uprobes.h b/runtime/uprobes2/uprobes.h index 112e29e2..ae0692f0 100644 --- a/runtime/uprobes2/uprobes.h +++ b/runtime/uprobes2/uprobes.h @@ -28,6 +28,9 @@ #define utrace_attached_engine utrace_engine #endif +/* Version 2 includes unmap_u[ret]probe(). */ +#define UPROBES_API_VERSION 2 + struct pt_regs; enum uprobe_type { @@ -82,6 +85,9 @@ extern void unregister_uprobe(struct uprobe *u); /* For runtime, assume uprobes support includes uretprobes. */ extern int register_uretprobe(struct uretprobe *rp); extern void unregister_uretprobe(struct uretprobe *rp); +/* For PRs 9940, 6852... */ +extern void unmap_uprobe(struct uprobe *u); +extern void unmap_uretprobe(struct uretprobe *rp); #ifdef UPROBES_IMPLEMENTATION diff --git a/runtime/uprobes2/uprobes_x86.c b/runtime/uprobes2/uprobes_x86.c index effb7444..8c80293d 100644 --- a/runtime/uprobes2/uprobes_x86.c +++ b/runtime/uprobes2/uprobes_x86.c @@ -50,8 +50,8 @@ static const u64 good_insns_64[256 / 64] = { W(0x50, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 50 */ W(0x60, 0,0,0,1,1,1,0,0,1,1,1,1,0,0,0,0)| /* 60 */ W(0x70, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), /* 70 */ - W(0x80, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 80 */ - W(0x90, 1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1)| /* 90 */ + W(0x80, 1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 80 */ + W(0x90, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 90 */ W(0xa0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* a0 */ W(0xb0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), /* b0 */ W(0xc0, 1,1,1,1,0,0,1,1,1,1,1,1,0,0,0,0)| /* c0 */ @@ -76,7 +76,7 @@ static const u64 good_insns_32[256 / 64] = { W(0x60, 1,1,1,0,1,1,0,0,1,1,1,1,0,0,0,0)| /* 60 */ W(0x70, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), /* 70 */ W(0x80, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 80 */ - W(0x90, 1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1)| /* 90 */ + W(0x90, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 90 */ W(0xa0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* a0 */ W(0xb0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), /* b0 */ W(0xc0, 1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0)| /* c0 */ @@ -124,7 +124,7 @@ static const u64 good_2byte_insns[256 / 64] = { * 0f - lar, lsl, syscall, clts, sysret, sysenter, sysexit, invd, wbinvd, ud2 * * invalid opcodes in 64-bit mode: - * 06, 0e, 16, 1e, 27, 2f, 37, 3f, 60-62, c4-c5, d4-d5 + * 06, 0e, 16, 1e, 27, 2f, 37, 3f, 60-62, 82, c4-c5, d4-d5 * * 63 - we support this opcode in x86_64 but not in i386. * opcodes we may need to refine support for: @@ -146,7 +146,6 @@ static const u64 good_2byte_insns[256 / 64] = { * 26, 2e, 36, 3e - es:, cs:, ss:, ds: segment prefixes -- * but 64 and 65 (fs: and gs:) seem to be used, so we support them * 67 - addr16 prefix - * 9b - wait/fwait * ce - into * f0 - lock prefix */ diff --git a/runtime/vsprintf.c b/runtime/vsprintf.c index bd58d760..38ab0e2d 100644 --- a/runtime/vsprintf.c +++ b/runtime/vsprintf.c @@ -12,6 +12,9 @@ #ifndef _VSPRINTF_C_ #define _VSPRINTF_C_ +//forward declaration for _stp_vsnprintf +static void * _stp_reserve_bytes (int); + static int skip_atoi(const char **s) { int i=0; @@ -22,6 +25,10 @@ static int skip_atoi(const char **s) enum print_flag {STP_ZEROPAD=1, STP_SIGN=2, STP_PLUS=4, STP_SPACE=8, STP_LEFT=16, STP_SPECIAL=32, STP_LARGE=64}; +/* + * Changes to number() will require a corresponding change to number_size below, + * to ensure proper buffer allocation for _stp_printf. + */ static char * number(char * buf, char * end, uint64_t num, int base, int size, int precision, enum print_flag type) { char c,sign,tmp[66]; @@ -115,6 +122,85 @@ static char * number(char * buf, char * end, uint64_t num, int base, int size, i return buf; } +/* + * Calculates the number of bytes required to print the paramater num. A change to + * number() requires a corresponding change here, and vice versa, to ensure the + * calculated size and printed size match. + */ +static int number_size(uint64_t num, int base, int size, int precision, enum print_flag type) { + char c,sign,tmp[66]; + const char *digits; + static const char small_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; + static const char large_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + int i, num_bytes = 0; + + digits = (type & STP_LARGE) ? large_digits : small_digits; + if (type & STP_LEFT) + type &= ~STP_ZEROPAD; + if (base < 2 || base > 36) + return 0; + c = (type & STP_ZEROPAD) ? '0' : ' '; + sign = 0; + if (type & STP_SIGN) { + if ((int64_t) num < 0) { + sign = '-'; + num = - (int64_t) num; + size--; + } else if (type & STP_PLUS) { + sign = '+'; + size--; + } else if (type & STP_SPACE) { + sign = ' '; + size--; + } + } + if (type & STP_SPECIAL) { + if (base == 16) + size -= 2; + else if (base == 8) + size--; + } + i = 0; + if (num == 0) + tmp[i++]='0'; + else while (num != 0) + tmp[i++] = digits[do_div(num,base)]; + if (i > precision) + precision = i; + size -= precision; + if (!(type&(STP_ZEROPAD+STP_LEFT))) { + while(size-->0) { + num_bytes++; + } + } + if (sign) { + num_bytes++; + } + if (type & STP_SPECIAL) { + if (base==8) { + num_bytes++; + } else if (base==16) { + num_bytes+=2; + } + } + if (!(type & STP_LEFT)) { + while (size-- > 0) { + num_bytes++; + } + } + while (i < precision--) { + num_bytes++; + } + while (i-- > 0) { + num_bytes++; + } + while (size-- > 0) { + num_bytes++; + } + return num_bytes; + +} + static int check_binary_precision (int precision) { /* precision can be unspecified (-1) or one of 1, 2, 4 or 8. */ switch (precision) { @@ -148,9 +234,262 @@ static int _stp_vsnprintf(char *buf, size_t size, const char *fmt, va_list args) if (unlikely((int) size < 0)) return 0; - str = buf; - end = buf + size - 1; + /* + * buf will be NULL when this function is called from _stp_printf. + * This branch calculates the exact size print buffer required for + * the string and allocates it with _stp_reserve_bytes. A change + * to this branch requires a corresponding change to the same + * section of code below. + */ + if (buf == NULL) { + const char* fmt_copy = fmt; + int num_bytes = 0; + va_list args_copy; + + va_copy(args_copy, args); + + for (; *fmt_copy ; ++fmt_copy) { + if (*fmt_copy != '%') { + num_bytes++; + continue; + } + + /* process flags */ + flags = 0; + repeat_copy: + ++fmt_copy; /* this also skips first '%' */ + switch (*fmt_copy) { + case '-': flags |= STP_LEFT; goto repeat_copy; + case '+': flags |= STP_PLUS; goto repeat_copy; + case ' ': flags |= STP_SPACE; goto repeat_copy; + case '#': flags |= STP_SPECIAL; goto repeat_copy; + case '0': flags |= STP_ZEROPAD; goto repeat_copy; + } + + /* get field width */ + field_width = -1; + if (isdigit(*fmt_copy)) + field_width = skip_atoi(&fmt_copy); + else if (*fmt_copy == '*') { + ++fmt_copy; + /* it's the next argument */ + field_width = va_arg(args_copy, int); + if (field_width < 0) { + field_width = -field_width; + flags |= STP_LEFT; + } + } + + /* get the precision */ + precision = -1; + if (*fmt_copy == '.') { + ++fmt_copy; + if (isdigit(*fmt_copy)) + precision = skip_atoi(&fmt_copy); + else if (*fmt_copy == '*') { + ++fmt_copy; + /* it's the next argument */ + precision = va_arg(args_copy, int); + } + if (precision < 0) + precision = 0; + } + + /* get the conversion qualifier */ + qualifier = -1; + if (*fmt_copy == 'h' || *fmt_copy == 'l' || *fmt_copy == 'L') { + qualifier = *fmt_copy; + ++fmt_copy; + if (qualifier == 'l' && *fmt_copy == 'l') { + qualifier = 'L'; + ++fmt_copy; + } + } + + /* default base */ + base = 10; + + switch (*fmt_copy) { + case 'b': + num = va_arg(args_copy, int64_t); + + /* Only certain values are valid for the precision. */ + precision = check_binary_precision (precision); + + /* Unspecified field width defaults to the specified + precision and vice versa. If neither is specified, + then both default to 8. */ + if (field_width == -1) { + if (precision == -1) { + field_width = 8; + precision = 8; + } + else + field_width = precision; + } + else if (precision == -1) { + precision = check_binary_precision (field_width); + if (precision == -1) + precision = 8; + } + + len = precision; + if (!(flags & STP_LEFT)) { + while (len < field_width--) { + num_bytes++; + } + } + + num_bytes += precision; + + while (len < field_width--) + num_bytes++; + + continue; + + case 's': + case 'M': + case 'm': + s = va_arg(args_copy, char *); + if ((unsigned long)s < PAGE_SIZE) + s = "<NULL>"; + + if (*fmt_copy == 's') + len = strnlen(s, precision); + else if (precision > 0) + len = precision; + else + len = 1; + + if (!(flags & STP_LEFT)) { + while (len < field_width--) { + num_bytes++; + } + } + if (*fmt_copy == 'M') { + num_bytes += number_size((unsigned long) *(uint64_t *) s, + 16, field_width, len, flags); + } + else { + num_bytes += len; + } + + while (len < field_width--) { + num_bytes++; + } + if(flags & STP_ZEROPAD) { + num_bytes++; + } + continue; + case 'X': + flags |= STP_LARGE; + case 'x': + base = 16; + break; + + case 'd': + case 'i': + flags |= STP_SIGN; + case 'u': + break; + + case 'p': + /* Note that %p takes an int64_t argument. */ + len = 2*sizeof(void *) + 2; + flags |= STP_ZEROPAD; + + if (field_width == -1) + field_width = len; + + if (!(flags & STP_LEFT)) { + while (len < field_width) { + field_width--; + num_bytes++; + } + } + + //account for "0x" + num_bytes+=2; + field_width-=2; + + num_bytes += number_size((unsigned long) va_arg(args_copy, int64_t), + 16, field_width, field_width, flags); + continue; + + case '%': + num_bytes++; + continue; + + /* integer number formats - set up the flags and "break" */ + case 'o': + base = 8; + break; + + case 'c': + if (!(flags & STP_LEFT)) { + while (--field_width > 0) { + num_bytes++; + } + } + c = (unsigned char) va_arg(args_copy, int); + num_bytes++; + while (--field_width > 0) { + num_bytes++; + } + continue; + + default: + num_bytes++; + if (*fmt_copy) { + num_bytes++; + } else { + --fmt_copy; + } + continue; + } + + if (qualifier == 'L') + num = va_arg(args_copy, int64_t); + else if (qualifier == 'l') { + num = va_arg(args_copy, unsigned long); + if (flags & STP_SIGN) + num = (signed long) num; + } else if (qualifier == 'h') { + num = (unsigned short) va_arg(args_copy, int); + if (flags & STP_SIGN) + num = (signed short) num; + } else { + num = va_arg(args_copy, unsigned int); + if (flags & STP_SIGN) + num = (signed int) num; + } + num_bytes += number_size(num, base, field_width, precision, flags); + } + + va_end(args_copy); + + if (num_bytes == 0) + return 0; + + //max print buffer size + if (num_bytes > STP_BUFFER_SIZE) { + num_bytes = STP_BUFFER_SIZE; + } + + str = (char*)_stp_reserve_bytes(num_bytes); + size = num_bytes; + end = str + size - 1; + + } else { + str = buf; + end = buf + size - 1; + } + /* + * Note that a change to code below requires a corresponding + * change in the code above to properly calculate the bytes + * required in the output buffer. + */ for (; *fmt ; ++fmt) { if (*fmt != '%') { if (str <= end) @@ -433,11 +772,13 @@ static int _stp_vsnprintf(char *buf, size_t size, const char *fmt, va_list args) field_width, precision, flags); } - if (likely(str <= end)) - *str = '\0'; - else if (size > 0) - /* don't write out a null byte if the buf size is zero */ - *end = '\0'; + if (buf != NULL) { + if (likely(str <= end)) + *str = '\0'; + else if (size > 0) + /* don't write out a null byte if the buf size is zero */ + *end = '\0'; + } return str-buf; } |