* Back to backtraces
2006-12-16 10:07 Performance monitoring hardware access for SystemTap William Cohen
@ 2006-12-16 10:13 ` Michael Grundy
0 siblings, 0 replies; 2+ messages in thread
From: Michael Grundy @ 2006-12-16 10:13 UTC (permalink / raw)
To: SystemTAP
Will's note about oprofile reminded me I had a jprobe module I meant to
inject into the backtrace discussions.I copped the backtrace code for a
jprobe module (included). It will go as far as it can up the chain, and
comparing with gdb backtraces seems pretty reliable.
Thanks
Mike
=========================================
Michael Grundy - grundym@us.ibm.com
Hey Phil, if we wanted to hit mailboxes we could let Ralph drive.
/* backtrace portions (c) 2002 OProfile authors, John Levon, David Smith
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/fs.h>
#include <linux/uio.h>
#include <linux/kprobes.h>
#include <linux/kallsyms.h>
#include <linux/smp_lock.h>
#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/oprofile.h>
#include <linux/mm.h>
#include <asm/processor.h>
#include <asm/ptrace.h>
#include <asm/uaccess.h>
char *jprobe_comm;
struct frame_head {
struct frame_head * ebp;
unsigned long ret;
} __attribute__((packed));
static struct frame_head *
dump_user_backtrace(struct frame_head * head)
{
struct frame_head bufhead[2];
/* Also check accessibility of one struct frame_head beyond */
if (!access_ok(VERIFY_READ, head, sizeof(bufhead)))
return NULL;
if (__copy_from_user_inatomic(bufhead, head, sizeof(bufhead)))
return NULL;
printk("[<%lx>]\n", bufhead[0].ret);
/* frame pointers should strictly progress back up the stack
* (towards higher addresses) */
if (head >= bufhead[0].ebp)
return NULL;
return bufhead[0].ebp;
}
void x86_backtrace(struct pt_regs * const regs, unsigned int depth)
{
struct frame_head *head;
#ifdef CONFIG_X86_64
head = (struct frame_head *)regs->rbp;
#else
head = (struct frame_head *)regs->ebp;
#endif
if (user_mode_vm(regs)) {
while (depth-- && head) {
printk("%3d: ", depth);
head = dump_user_backtrace(head);
}
}
}
int jdo_exit(long code)
{
struct task_struct *t = current;
extern char *jprobe_comm;
/*
* dump stack when specified process exits
*/
if (strcmp(t->comm, jprobe_comm) == 0) {
printk("process(%d:%s) is exiting\n....", t->pid,
t->comm);
printk("exit_code: 0x%lx, flags: 0x%lx\n....", code,
t->flags);
if (t->thread_info)
printk("thread flags: 0x%lx, status: 0x%lx, cpu:
%d\n",
t->thread_info->flags,
t->thread_info->status,
t->thread_info->cpu);
dump_stack();
/* ebp is the last reg pushed by switch_to */
printk("user backtrace\neip: [<%lx>]\n",
task_pt_regs(t)->eip);
x86_backtrace(task_pt_regs(t), 30);
}
/* Always end with a call to jprobe_return(). */
jprobe_return();
/*NOTREACHED*/
return 0;
}
static struct jprobe my_jprobe = {
.entry = (kprobe_opcode_t *) jdo_exit
};
int init_module(void)
{
int ret;
char *func = "do_exit";
if (jprobe_comm == NULL) {
printk("Command to probe not specified.\n");
return -1;
}
my_jprobe.kp.addr = (kprobe_opcode_t *)
kallsyms_lookup_name(func);
if (!my_jprobe.kp.addr) {
printk("Couldn't find %s to plant jprobe\n", func);
return -1;
}
if ((ret = register_jprobe(&my_jprobe)) <0) {
printk("register_jprobe failed, returned %d\n", ret);
return -1;
}
printk("Planted jprobe at %p, handler addr %p\n",
my_jprobe.kp.addr, my_jprobe.entry);
printk("Probing command: %s\n", jprobe_comm);
return 0;
}
void cleanup_module(void)
{
unregister_jprobe(&my_jprobe);
printk("jprobe unregistered\n");
}
MODULE_LICENSE("GPL");
module_param(jprobe_comm, charp, 0444);
MODULE_PARM_DESC(jprobe_comm, "Name of command to probe.");
^ permalink raw reply [flat|nested] 2+ messages in thread