summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorbs21162 <none@none>2007-02-14 07:03:29 -0800
committerbs21162 <none@none>2007-02-14 07:03:29 -0800
commit4df4bd6096e60a7062ad804cc29ac7cc4b03811a (patch)
tree367200e5346989cdc82a74a1b99750377d9c13c8 /usr/src
parent13b62818935f17649076850c24d566bd5bd6aa1a (diff)
downloadillumos-gate-4df4bd6096e60a7062ad804cc29ac7cc4b03811a.tar.gz
5073041 enhancing Ftrace to get the caller information
6457723 DR causes memory leak of ftrace buffers
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/uts/common/os/ftrace.c276
-rw-r--r--usr/src/uts/common/sys/cpuvar.h2
-rw-r--r--usr/src/uts/common/sys/ftrace.h32
-rw-r--r--usr/src/uts/intel/ia32/ml/i86_subr.s59
-rw-r--r--usr/src/uts/sparc/v9/ml/sparcv9_subr.s41
-rw-r--r--usr/src/uts/sun4/ml/interrupt.s5
6 files changed, 320 insertions, 95 deletions
diff --git a/usr/src/uts/common/os/ftrace.c b/usr/src/uts/common/os/ftrace.c
index 5a31175701..0645759dfb 100644
--- a/usr/src/uts/common/os/ftrace.c
+++ b/usr/src/uts/common/os/ftrace.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 1998-2003 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -49,7 +48,24 @@ int ftrace_atboot = 0;
int ftrace_nent = FTRACE_NENT;
/*
- * The current overall state of the ftrace subsystem.
+ * Global Tracing State:
+ *
+ * NOTREADY(=0)
+ * |
+ * ftrace_init()
+ * |
+ * |
+ * v
+ * +-------->READY-------+
+ * | |
+ * ftrace_stop() ftrace_start()
+ * | |
+ * +---(ENABLED|READY)<--+
+ *
+ * During boot, ftrace_init() is called and the state becomes
+ * READY. If ftrace_atboot is set, ftrace_start() is called at
+ * this time.
+ *
* If FTRACE_READY is set, then tracing can be enabled.
* If FTRACE_ENABLED is set, tracing is enabled on the set of CPUs
* which are currently FTRACE_READY.
@@ -57,16 +73,53 @@ int ftrace_nent = FTRACE_NENT;
static int ftrace_state = 0;
/*
- * Protects assignments to:
+ * Per-CPU Tracing State:
+ *
+ * +-----------------READY<--------------+
+ * | ^ | |
+ * | | ftrace_cpu_fini() |
+ * | | | |
+ * | ftrace_cpu_init() | |
+ * | | v ftrace_cpu_stop()
+ * | NOTREADY(=0) |
+ * | ^ |
+ * ftrace_cpu_start() | |
+ * | ftrace_cpu_fini() |
+ * | | |
+ * +----------->(ENABLED|READY)----------+
+ *
+ */
+
+/*
+ * Locking :
+ *
+ * Trace context code does not use any lock. There is a per-cpu circular trace
+ * buffer that has a head, a tail and a current pointer. Each record of this
+ * buffer is of equal length. Before doing anything, trace context code checks
+ * the per-cpu ENABLED bit. Trace buffer is allocated in non-trace context and
+ * it sets this bit only after allocating and setting up the buffer. So trace
+ * context code can't access the buffer till it is set up completely. The
+ * buffer is freed also in non-trace context. The code that frees the buffer is
+ * executed only after the corresponding cpu is powered off. So when this
+ * happens, no trace context code can be running on it. We only need to make
+ * sure that trace context code is not preempted from the cpu in the middle of
+ * accessing the trace buffer. This can be achieved simply by disabling
+ * interrupts temporarily. This approach makes the least assumption about the
+ * state of the callers of tracing functions.
+ *
+ * A single global lock, ftrace_lock protects assignments to all global and
+ * per-cpu trace variables. It does not protect reading of those in some cases.
+ *
+ * More specifically, it protects assignments to:
+ *
* ftrace_state
* cpu[N]->cpu_ftrace.ftd_state
- * cpu[N]->cpu_ftrace.ftd_cur
* cpu[N]->cpu_ftrace.ftd_first
* cpu[N]->cpu_ftrace.ftd_last
- * Does _not_ protect readers of cpu[N]->cpu_ftrace.ftd_state.
- * Does not protect reading the FTRACE_READY bit in ftrace_state,
- * since non-READY to READY is a stable transition. This is used
- * to ensure ftrace_init() has been called.
+ *
+ * Does _not_ protect reading of cpu[N]->cpu_ftrace.ftd_state
+ * Does _not_ protect cpu[N]->cpu_ftrace.ftd_cur
+ * Does _not_ protect reading of ftrace_state
*/
static kmutex_t ftrace_lock;
@@ -119,11 +172,18 @@ ftrace_cpu_fini(int cpuid)
return;
/*
- * Do not free mutex and the the trace buffer once they are
- * allocated. A thread, preempted from the now powered-off CPU
- * may be holding the mutex and in the middle of adding a trace
- * record.
+ * This cpu is powered off and no code can be executing on it. So
+ * we can simply finish our cleanup. There is no need for a xcall
+ * to make sure that this cpu is out of trace context.
+ *
+ * The cpu structure will be cleared soon. But, for the sake of
+ * debugging, clear our pointers and state.
*/
+ if (ftd->ftd_first != NULL) {
+ kmem_free(ftd->ftd_first,
+ ftrace_nent * sizeof (ftrace_record_t));
+ }
+ bzero(ftd, sizeof (ftrace_data_t));
}
static void
@@ -140,11 +200,19 @@ ftrace_cpu_start(int cpuid)
if (ftd->ftd_first == NULL) {
ftrace_record_t *ptrs;
- mutex_init(&ftd->ftd_mutex, NULL, MUTEX_DEFAULT, NULL);
mutex_exit(&ftrace_lock);
ptrs = kmem_zalloc(ftrace_nent *
sizeof (ftrace_record_t), KM_SLEEP);
mutex_enter(&ftrace_lock);
+ if (ftd->ftd_first != NULL) {
+ /*
+ * Someone else beat us to it. The winner will
+ * set up the pointers and the state.
+ */
+ kmem_free(ptrs,
+ ftrace_nent * sizeof (ftrace_record_t));
+ return;
+ }
ftd->ftd_first = ptrs;
ftd->ftd_last = ptrs + (ftrace_nent - 1);
@@ -232,6 +300,9 @@ ftrace_init(void)
(void) ftrace_start();
}
+/*
+ * Called from uadmin ioctl, or via mp_init_table[] during boot.
+ */
int
ftrace_start(void)
{
@@ -250,6 +321,9 @@ ftrace_start(void)
return (was_enabled);
}
+/*
+ * Called from uadmin ioctl, to stop tracing.
+ */
int
ftrace_stop(void)
{
@@ -269,102 +343,146 @@ ftrace_stop(void)
return (was_enabled);
}
+/*
+ * ftrace_X() functions are called from trace context. All callers of ftrace_X()
+ * tests FTRACE_ENABLED first. Although this is not very accurate, it keeps the
+ * overhead very low when tracing is not enabled.
+ *
+ * gethrtime_unscaled() appears to be safe to be called in trace context. As an
+ * added precaution, we call these before we disable interrupts on this cpu.
+ */
+
void
-ftrace_0(char *str)
+ftrace_0(char *str, caddr_t caller)
{
ftrace_record_t *r;
- struct cpu *cp = CPU;
- ftrace_data_t *ftd = &cp->cpu_ftrace;
-
- if (mutex_tryenter(&ftd->ftd_mutex) == 0) {
- if (CPU_ON_INTR(cp))
- return;
- else
- mutex_enter(&ftd->ftd_mutex);
+ struct cpu *cp;
+ ftrace_data_t *ftd;
+ ftrace_icookie_t cookie;
+ hrtime_t timestamp;
+
+ timestamp = gethrtime_unscaled();
+
+ cookie = ftrace_interrupt_disable();
+
+ cp = CPU;
+ ftd = &cp->cpu_ftrace;
+
+ if (!(ftd->ftd_state & FTRACE_ENABLED)) {
+ ftrace_interrupt_enable(cookie);
+ return;
}
+
r = ftd->ftd_cur;
r->ftr_event = str;
r->ftr_thread = curthread;
- r->ftr_tick = gethrtime_unscaled();
- r->ftr_caller = caller();
+ r->ftr_tick = timestamp;
+ r->ftr_caller = caller;
if (r++ == ftd->ftd_last)
r = ftd->ftd_first;
ftd->ftd_cur = r;
- mutex_exit(&ftd->ftd_mutex);
+
+ ftrace_interrupt_enable(cookie);
}
void
-ftrace_1(char *str, ulong_t arg1)
+ftrace_1(char *str, ulong_t arg1, caddr_t caller)
{
ftrace_record_t *r;
- struct cpu *cp = CPU;
- ftrace_data_t *ftd = &cp->cpu_ftrace;
-
- if (mutex_tryenter(&ftd->ftd_mutex) == 0) {
- if (CPU_ON_INTR(cp))
- return;
- else
- mutex_enter(&ftd->ftd_mutex);
+ struct cpu *cp;
+ ftrace_data_t *ftd;
+ ftrace_icookie_t cookie;
+ hrtime_t timestamp;
+
+ timestamp = gethrtime_unscaled();
+
+ cookie = ftrace_interrupt_disable();
+
+ cp = CPU;
+ ftd = &cp->cpu_ftrace;
+
+ if (!(ftd->ftd_state & FTRACE_ENABLED)) {
+ ftrace_interrupt_enable(cookie);
+ return;
}
+
r = ftd->ftd_cur;
r->ftr_event = str;
r->ftr_thread = curthread;
- r->ftr_tick = gethrtime_unscaled();
- r->ftr_caller = caller();
+ r->ftr_tick = timestamp;
+ r->ftr_caller = caller;
r->ftr_data1 = arg1;
if (r++ == ftd->ftd_last)
r = ftd->ftd_first;
ftd->ftd_cur = r;
- mutex_exit(&ftd->ftd_mutex);
+
+ ftrace_interrupt_enable(cookie);
}
void
-ftrace_2(char *str, ulong_t arg1, ulong_t arg2)
+ftrace_2(char *str, ulong_t arg1, ulong_t arg2, caddr_t caller)
{
ftrace_record_t *r;
- struct cpu *cp = CPU;
- ftrace_data_t *ftd = &cp->cpu_ftrace;
-
- if (mutex_tryenter(&ftd->ftd_mutex) == 0) {
- if (CPU_ON_INTR(cp))
- return;
- else
- mutex_enter(&ftd->ftd_mutex);
+ struct cpu *cp;
+ ftrace_data_t *ftd;
+ ftrace_icookie_t cookie;
+ hrtime_t timestamp;
+
+ timestamp = gethrtime_unscaled();
+
+ cookie = ftrace_interrupt_disable();
+
+ cp = CPU;
+ ftd = &cp->cpu_ftrace;
+
+ if (!(ftd->ftd_state & FTRACE_ENABLED)) {
+ ftrace_interrupt_enable(cookie);
+ return;
}
+
r = ftd->ftd_cur;
r->ftr_event = str;
r->ftr_thread = curthread;
- r->ftr_tick = gethrtime_unscaled();
- r->ftr_caller = caller();
+ r->ftr_tick = timestamp;
+ r->ftr_caller = caller;
r->ftr_data1 = arg1;
r->ftr_data2 = arg2;
if (r++ == ftd->ftd_last)
r = ftd->ftd_first;
ftd->ftd_cur = r;
- mutex_exit(&ftd->ftd_mutex);
+
+ ftrace_interrupt_enable(cookie);
}
void
-ftrace_3(char *str, ulong_t arg1, ulong_t arg2, ulong_t arg3)
+ftrace_3(char *str, ulong_t arg1, ulong_t arg2, ulong_t arg3, caddr_t caller)
{
ftrace_record_t *r;
- struct cpu *cp = CPU;
- ftrace_data_t *ftd = &cp->cpu_ftrace;
-
- if (mutex_tryenter(&ftd->ftd_mutex) == 0) {
- if (CPU_ON_INTR(cp))
- return;
- else
- mutex_enter(&ftd->ftd_mutex);
+ struct cpu *cp;
+ ftrace_data_t *ftd;
+ ftrace_icookie_t cookie;
+ hrtime_t timestamp;
+
+ timestamp = gethrtime_unscaled();
+
+ cookie = ftrace_interrupt_disable();
+
+ cp = CPU;
+ ftd = &cp->cpu_ftrace;
+
+ if (!(ftd->ftd_state & FTRACE_ENABLED)) {
+ ftrace_interrupt_enable(cookie);
+ return;
}
+
r = ftd->ftd_cur;
r->ftr_event = str;
r->ftr_thread = curthread;
- r->ftr_tick = gethrtime_unscaled();
- r->ftr_caller = caller();
+ r->ftr_tick = timestamp;
+ r->ftr_caller = caller;
r->ftr_data1 = arg1;
r->ftr_data2 = arg2;
r->ftr_data3 = arg3;
@@ -372,27 +490,34 @@ ftrace_3(char *str, ulong_t arg1, ulong_t arg2, ulong_t arg3)
if (r++ == ftd->ftd_last)
r = ftd->ftd_first;
ftd->ftd_cur = r;
- mutex_exit(&ftd->ftd_mutex);
+
+ ftrace_interrupt_enable(cookie);
}
void
-ftrace_3_notick(char *str, ulong_t arg1, ulong_t arg2, ulong_t arg3)
+ftrace_3_notick(char *str, ulong_t arg1, ulong_t arg2,
+ ulong_t arg3, caddr_t caller)
{
ftrace_record_t *r;
- struct cpu *cp = CPU;
- ftrace_data_t *ftd = &cp->cpu_ftrace;
-
- if (mutex_tryenter(&ftd->ftd_mutex) == 0) {
- if (CPU_ON_INTR(cp))
- return;
- else
- mutex_enter(&ftd->ftd_mutex);
+ struct cpu *cp;
+ ftrace_data_t *ftd;
+ ftrace_icookie_t cookie;
+
+ cookie = ftrace_interrupt_disable();
+
+ cp = CPU;
+ ftd = &cp->cpu_ftrace;
+
+ if (!(ftd->ftd_state & FTRACE_ENABLED)) {
+ ftrace_interrupt_enable(cookie);
+ return;
}
+
r = ftd->ftd_cur;
r->ftr_event = str;
r->ftr_thread = curthread;
r->ftr_tick = 0;
- r->ftr_caller = caller();
+ r->ftr_caller = caller;
r->ftr_data1 = arg1;
r->ftr_data2 = arg2;
r->ftr_data3 = arg3;
@@ -400,5 +525,6 @@ ftrace_3_notick(char *str, ulong_t arg1, ulong_t arg2, ulong_t arg3)
if (r++ == ftd->ftd_last)
r = ftd->ftd_first;
ftd->ftd_cur = r;
- mutex_exit(&ftd->ftd_mutex);
+
+ ftrace_interrupt_enable(cookie);
}
diff --git a/usr/src/uts/common/sys/cpuvar.h b/usr/src/uts/common/sys/cpuvar.h
index 0af0d086a9..f3dc26f874 100644
--- a/usr/src/uts/common/sys/cpuvar.h
+++ b/usr/src/uts/common/sys/cpuvar.h
@@ -71,7 +71,7 @@ struct loadavg_s {
struct ftrace_record;
typedef struct ftrace_data {
int ftd_state; /* ftrace flags */
- kmutex_t ftd_mutex; /* ftrace buffer lock */
+ kmutex_t ftd_unused; /* ftrace buffer lock, unused */
struct ftrace_record *ftd_cur; /* current record */
struct ftrace_record *ftd_first; /* first record */
struct ftrace_record *ftd_last; /* last record */
diff --git a/usr/src/uts/common/sys/ftrace.h b/usr/src/uts/common/sys/ftrace.h
index f10fff5549..8fa940d62b 100644
--- a/usr/src/uts/common/sys/ftrace.h
+++ b/usr/src/uts/common/sys/ftrace.h
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,8 +19,8 @@
* CDDL HEADER END
*/
/*
- * Copyright (c) 1998 by Sun Microsystems, Inc.
- * All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
*/
#ifndef _SYS_FTRACE_H
@@ -87,30 +86,37 @@ extern int ftrace_cpu_setup(cpu_setup_t, int, void *);
extern void ftrace_init(void);
extern int ftrace_start(void);
extern int ftrace_stop(void);
-extern void ftrace_0(char *);
-extern void ftrace_1(char *, ulong_t);
-extern void ftrace_2(char *, ulong_t, ulong_t);
-extern void ftrace_3(char *, ulong_t, ulong_t, ulong_t);
+extern void ftrace_0(char *, caddr_t);
+extern void ftrace_1(char *, ulong_t, caddr_t);
+extern void ftrace_2(char *, ulong_t, ulong_t, caddr_t);
+extern void ftrace_3(char *, ulong_t, ulong_t, ulong_t, caddr_t);
+extern void ftrace_3_notick(char *, ulong_t, ulong_t, ulong_t,
+ caddr_t);
+
+typedef uintptr_t ftrace_icookie_t;
+extern ftrace_icookie_t ftrace_interrupt_disable(void);
+extern void ftrace_interrupt_enable(ftrace_icookie_t);
+extern caddr_t caller(void);
#define FTRACE_0(fmt) \
{ \
if (CPU->cpu_ftrace.ftd_state & FTRACE_ENABLED) \
- ftrace_0(fmt); \
+ ftrace_0(fmt, caller()); \
}
#define FTRACE_1(fmt, d1) \
{ \
if (CPU->cpu_ftrace.ftd_state & FTRACE_ENABLED) \
- ftrace_1(fmt, d1); \
+ ftrace_1(fmt, d1, caller()); \
}
#define FTRACE_2(fmt, d1, d2) \
{ \
if (CPU->cpu_ftrace.ftd_state & FTRACE_ENABLED) \
- ftrace_2(fmt, d1, d2); \
+ ftrace_2(fmt, d1, d2, caller()); \
}
#define FTRACE_3(fmt, d1, d2, d3) \
{ \
if (CPU->cpu_ftrace.ftd_state & FTRACE_ENABLED) \
- ftrace_3(fmt, d1, d2, d3); \
+ ftrace_3(fmt, d1, d2, d3, caller()); \
}
#define FTRACE_START() ftrace_start()
#define FTRACE_STOP() ftrace_stop()
diff --git a/usr/src/uts/intel/ia32/ml/i86_subr.s b/usr/src/uts/intel/ia32/ml/i86_subr.s
index 18a06ebdf1..480de7b928 100644
--- a/usr/src/uts/intel/ia32/ml/i86_subr.s
+++ b/usr/src/uts/intel/ia32/ml/i86_subr.s
@@ -59,6 +59,7 @@
#include <sys/archsystm.h>
#include <sys/byteorder.h>
#include <sys/dtrace.h>
+#include <sys/ftrace.h>
#else /* __lint */
#include "assym.h"
#endif /* __lint */
@@ -3708,3 +3709,61 @@ getflags(void)
#endif /* __i386 */
#endif /* __lint */
+
+#if defined(__lint)
+
+ftrace_icookie_t
+ftrace_interrupt_disable(void)
+{ return (0); }
+
+#else /* __lint */
+
+#if defined(__amd64)
+
+ ENTRY(ftrace_interrupt_disable)
+ pushfq
+ popq %rax
+ CLI(%rdx)
+ ret
+ SET_SIZE(ftrace_interrupt_disable)
+
+#elif defined(__i386)
+
+ ENTRY(ftrace_interrupt_disable)
+ pushfl
+ popl %eax
+ CLI(%edx)
+ ret
+ SET_SIZE(ftrace_interrupt_disable)
+
+#endif /* __i386 */
+#endif /* __lint */
+
+#if defined(__lint)
+
+/*ARGSUSED*/
+void
+ftrace_interrupt_enable(ftrace_icookie_t cookie)
+{}
+
+#else /* __lint */
+
+#if defined(__amd64)
+
+ ENTRY(ftrace_interrupt_enable)
+ pushq %rdi
+ popfq
+ ret
+ SET_SIZE(ftrace_interrupt_enable)
+
+#elif defined(__i386)
+
+ ENTRY(ftrace_interrupt_enable)
+ movl 4(%esp), %eax
+ pushl %eax
+ popfl
+ ret
+ SET_SIZE(ftrace_interrupt_enable)
+
+#endif /* __i386 */
+#endif /* __lint */
diff --git a/usr/src/uts/sparc/v9/ml/sparcv9_subr.s b/usr/src/uts/sparc/v9/ml/sparcv9_subr.s
index f0c9830583..cb23034e4b 100644
--- a/usr/src/uts/sparc/v9/ml/sparcv9_subr.s
+++ b/usr/src/uts/sparc/v9/ml/sparcv9_subr.s
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -46,6 +45,7 @@
#include <sys/sunddi.h>
#include <sys/lockstat.h>
#include <sys/dtrace.h>
+#include <sys/ftrace.h>
#endif /* lint */
#include <sys/asm_linkage.h>
@@ -1772,3 +1772,36 @@ get_subcc_ccr( uint64_t addrl, uint64_t addrr)
SET_SIZE(get_subcc_ccr)
#endif /* lint */
+
+#if defined(lint) || defined(__lint)
+
+ftrace_icookie_t
+ftrace_interrupt_disable(void)
+{ return (0); }
+
+#else /* lint */
+
+ ENTRY_NP(ftrace_interrupt_disable)
+ rdpr %pstate, %o0
+ andn %o0, PSTATE_IE, %o1
+ retl
+ wrpr %g0, %o1, %pstate
+ SET_SIZE(ftrace_interrupt_disable)
+
+#endif /* lint */
+
+#if defined(lint) || defined(__lint)
+
+/*ARGSUSED*/
+void
+ftrace_interrupt_enable(ftrace_icookie_t cookie)
+{}
+
+#else
+
+ ENTRY_NP(ftrace_interrupt_enable)
+ retl
+ wrpr %g0, %o0, %pstate
+ SET_SIZE(ftrace_interrupt_enable)
+
+#endif /* lint*/
diff --git a/usr/src/uts/sun4/ml/interrupt.s b/usr/src/uts/sun4/ml/interrupt.s
index 930f35734f..b3055e0317 100644
--- a/usr/src/uts/sun4/ml/interrupt.s
+++ b/usr/src/uts/sun4/ml/interrupt.s
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -547,8 +547,9 @@ intr_thread(struct regs *regs, uint64_t iv_p, uint_t pil)
set ftrace_intr_thread_format_str, %o0
mov %i0, %o1
mov %i1, %o2
- call ftrace_3
mov %i5, %o3
+ call ftrace_3
+ ldn [%i0 + PC_OFF], %o4
restore
1:
!