add some new files missed by my script:
merge a new version of the CDDL dtrace and ZFS code. this changes the upstream vendor from OpenSolaris to FreeBSD, and this version is based on FreeBSD svn r315983. in addition to the 10 years of improvements from upstream, this version also has these NetBSD-specific enhancements: - dtrace FBT probes can now be placed in kernel modules. - ZFS now supports mmap().
This commit is contained in:
parent
c565efa5f0
commit
710a39faba
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* 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.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
/* Copyright (c) 1988 AT&T */
|
||||
/* All Rights Reserved */
|
||||
|
||||
/*
|
||||
* $FreeBSD: head/sys/cddl/dev/dtrace/x86/dis_tables.h 313133 2017-02-03 03:22:47Z markj $
|
||||
*/
|
||||
|
||||
#ifndef _DIS_TABLES_H
|
||||
#define _DIS_TABLES_H
|
||||
|
||||
/*
|
||||
* Constants and prototypes for the IA32 disassembler backend. See dis_tables.c
|
||||
* for usage information and documentation.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
/*
|
||||
* values for cpu mode
|
||||
*/
|
||||
#define SIZE16 1
|
||||
#define SIZE32 2
|
||||
#define SIZE64 3
|
||||
|
||||
#define OPLEN 256
|
||||
#define PFIXLEN 8
|
||||
#define NCPS 20 /* number of chars per symbol */
|
||||
|
||||
/*
|
||||
* data structures that must be provided to dtrace_dis86()
|
||||
*/
|
||||
typedef struct d86opnd {
|
||||
char d86_opnd[OPLEN]; /* symbolic rep of operand */
|
||||
char d86_prefix[PFIXLEN]; /* any prefix string or "" */
|
||||
uint_t d86_mode; /* mode for immediate */
|
||||
uint_t d86_value_size; /* size in bytes of d86_value */
|
||||
uint64_t d86_value; /* immediate value of opnd */
|
||||
} d86opnd_t;
|
||||
|
||||
typedef struct dis86 {
|
||||
uint_t d86_mode;
|
||||
uint_t d86_error;
|
||||
uint_t d86_len; /* instruction length */
|
||||
int d86_rmindex; /* index of modrm byte or -1 */
|
||||
uint_t d86_memsize; /* size of memory referenced */
|
||||
char d86_bytes[16]; /* bytes of instruction */
|
||||
char d86_mnem[OPLEN];
|
||||
uint_t d86_numopnds;
|
||||
uint_t d86_rex_prefix; /* value of REX prefix if !0 */
|
||||
char *d86_seg_prefix; /* segment prefix, if any */
|
||||
uint_t d86_opnd_size;
|
||||
uint_t d86_addr_size;
|
||||
uint_t d86_got_modrm;
|
||||
uint_t d86_vsib; /* Has a VSIB */
|
||||
struct d86opnd d86_opnd[4]; /* up to 4 operands */
|
||||
int (*d86_check_func)(void *);
|
||||
int (*d86_get_byte)(void *);
|
||||
#ifdef DIS_TEXT
|
||||
int (*d86_sym_lookup)(void *, uint64_t, char *, size_t);
|
||||
int (*d86_sprintf_func)(char *, size_t, const char *, ...);
|
||||
int d86_flags;
|
||||
uint_t d86_imm_bytes;
|
||||
#endif
|
||||
void *d86_data;
|
||||
} dis86_t;
|
||||
|
||||
extern int dtrace_disx86(dis86_t *x, uint_t cpu_mode);
|
||||
|
||||
#define DIS_F_OCTAL 0x1 /* Print all numbers in octal */
|
||||
#define DIS_F_NOIMMSYM 0x2 /* Don't print symbols for immediates (.o) */
|
||||
|
||||
#ifdef DIS_TEXT
|
||||
extern void dtrace_disx86_str(dis86_t *x, uint_t cpu_mode, uint64_t pc,
|
||||
char *buf, size_t len);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _DIS_TABLES_H */
|
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*
|
||||
* $FreeBSD: head/sys/cddl/dev/dtrace/x86/instr_size.c 303050 2016-07-20 00:02:10Z markj $
|
||||
*/
|
||||
/*
|
||||
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
/* Copyright (c) 1988 AT&T */
|
||||
/* All Rights Reserved */
|
||||
|
||||
|
||||
#ifdef illumos
|
||||
#pragma ident "@(#)instr_size.c 1.14 05/07/08 SMI"
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/param.h>
|
||||
#ifdef illumos
|
||||
#include <sys/cmn_err.h>
|
||||
#include <sys/archsystm.h>
|
||||
#include <sys/copyops.h>
|
||||
#include <vm/seg_enum.h>
|
||||
#include <sys/privregs.h>
|
||||
#endif
|
||||
#ifdef __FreeBSD__
|
||||
#include <sys/cred.h>
|
||||
#include <cddl/dev/dtrace/dtrace_cddl.h>
|
||||
|
||||
typedef u_int model_t;
|
||||
#define DATAMODEL_NATIVE 0
|
||||
int dtrace_instr_size(uchar_t *);
|
||||
int dtrace_instr_size_isa(uchar_t *, model_t, int *);
|
||||
#endif
|
||||
#ifdef __NetBSD__
|
||||
#include <dtrace_cddl.h>
|
||||
|
||||
typedef u_int model_t;
|
||||
#define DATAMODEL_NATIVE 0
|
||||
int dtrace_instr_size(uchar_t *);
|
||||
int dtrace_instr_size_isa(uchar_t *, model_t, int *);
|
||||
#endif
|
||||
|
||||
#include <dis_tables.h>
|
||||
|
||||
/*
|
||||
* This subsystem (with the minor exception of the instr_size() function) is
|
||||
* is called from DTrace probe context. This imposes several requirements on
|
||||
* the implementation:
|
||||
*
|
||||
* 1. External subsystems and functions may not be referenced. The one current
|
||||
* exception is for cmn_err, but only to signal the detection of table
|
||||
* errors. Assuming the tables are correct, no combination of input is to
|
||||
* trigger a cmn_err call.
|
||||
*
|
||||
* 2. These functions can't be allowed to be traced. To prevent this,
|
||||
* all functions in the probe path (everything except instr_size()) must
|
||||
* have names that begin with "dtrace_".
|
||||
*/
|
||||
|
||||
typedef enum dis_isize {
|
||||
DIS_ISIZE_INSTR,
|
||||
DIS_ISIZE_OPERAND
|
||||
} dis_isize_t;
|
||||
|
||||
|
||||
/*
|
||||
* get a byte from instruction stream
|
||||
*/
|
||||
static int
|
||||
dtrace_dis_get_byte(void *p)
|
||||
{
|
||||
int ret;
|
||||
uchar_t **instr = p;
|
||||
|
||||
ret = **instr;
|
||||
*instr += 1;
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns either the size of a given instruction, in bytes, or the size of that
|
||||
* instruction's memory access (if any), depending on the value of `which'.
|
||||
* If a programming error in the tables is detected, the system will panic to
|
||||
* ease diagnosis. Invalid instructions will not be flagged. They will appear
|
||||
* to have an instruction size between 1 and the actual size, and will be
|
||||
* reported as having no memory impact.
|
||||
*/
|
||||
/* ARGSUSED2 */
|
||||
static int
|
||||
dtrace_dis_isize(uchar_t *instr, dis_isize_t which, model_t model, int *rmindex)
|
||||
{
|
||||
int sz;
|
||||
dis86_t x;
|
||||
uint_t mode = SIZE32;
|
||||
|
||||
mode = (model == DATAMODEL_LP64) ? SIZE64 : SIZE32;
|
||||
|
||||
x.d86_data = (void **)&instr;
|
||||
x.d86_get_byte = dtrace_dis_get_byte;
|
||||
x.d86_check_func = NULL;
|
||||
|
||||
if (dtrace_disx86(&x, mode) != 0)
|
||||
return (-1);
|
||||
|
||||
if (which == DIS_ISIZE_INSTR)
|
||||
sz = x.d86_len; /* length of the instruction */
|
||||
else
|
||||
sz = x.d86_memsize; /* length of memory operand */
|
||||
|
||||
if (rmindex != NULL)
|
||||
*rmindex = x.d86_rmindex;
|
||||
return (sz);
|
||||
}
|
||||
|
||||
int
|
||||
dtrace_instr_size_isa(uchar_t *instr, model_t model, int *rmindex)
|
||||
{
|
||||
return (dtrace_dis_isize(instr, DIS_ISIZE_INSTR, model, rmindex));
|
||||
}
|
||||
|
||||
int
|
||||
dtrace_instr_size(uchar_t *instr)
|
||||
{
|
||||
return (dtrace_dis_isize(instr, DIS_ISIZE_INSTR, DATAMODEL_NATIVE,
|
||||
NULL));
|
||||
}
|
|
@ -0,0 +1,178 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*
|
||||
* $FreeBSD: head/sys/cddl/dev/dtrace/x86/regset.h 277300 2015-01-17 14:44:59Z smh $
|
||||
*/
|
||||
/*
|
||||
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
/* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */
|
||||
|
||||
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
|
||||
/* All Rights Reserved */
|
||||
|
||||
#ifndef _REGSET_H
|
||||
#define _REGSET_H
|
||||
|
||||
/*
|
||||
* #pragma ident "@(#)regset.h 1.11 05/06/08 SMI"
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The names and offsets defined here should be specified by the
|
||||
* AMD64 ABI suppl.
|
||||
*
|
||||
* We make fsbase and gsbase part of the lwp context (since they're
|
||||
* the only way to access the full 64-bit address range via the segment
|
||||
* registers) and thus belong here too. However we treat them as
|
||||
* read-only; if %fs or %gs are updated, the results of the descriptor
|
||||
* table lookup that those updates implicitly cause will be reflected
|
||||
* in the corresponding fsbase and/or gsbase values the next time the
|
||||
* context can be inspected. However it is NOT possible to override
|
||||
* the fsbase/gsbase settings via this interface.
|
||||
*
|
||||
* Direct modification of the base registers (thus overriding the
|
||||
* descriptor table base address) can be achieved with _lwp_setprivate.
|
||||
*/
|
||||
|
||||
#define REG_GSBASE 27
|
||||
#define REG_FSBASE 26
|
||||
#ifdef illumos
|
||||
#define REG_DS 25
|
||||
#define REG_ES 24
|
||||
|
||||
#define REG_GS 23
|
||||
#define REG_FS 22
|
||||
#define REG_SS 21
|
||||
#define REG_RSP 20
|
||||
#define REG_RFL 19
|
||||
#define REG_CS 18
|
||||
#define REG_RIP 17
|
||||
#define REG_ERR 16
|
||||
#define REG_TRAPNO 15
|
||||
#define REG_RAX 14
|
||||
#define REG_RCX 13
|
||||
#define REG_RDX 12
|
||||
#define REG_RBX 11
|
||||
#define REG_RBP 10
|
||||
#define REG_RSI 9
|
||||
#define REG_RDI 8
|
||||
#define REG_R8 7
|
||||
#define REG_R9 6
|
||||
#define REG_R10 5
|
||||
#define REG_R11 4
|
||||
#define REG_R12 3
|
||||
#define REG_R13 2
|
||||
#define REG_R14 1
|
||||
#define REG_R15 0
|
||||
#else /* !illumos */
|
||||
#define REG_SS 25
|
||||
#define REG_RSP 24
|
||||
#define REG_RFL 23
|
||||
#define REG_CS 22
|
||||
#define REG_RIP 21
|
||||
#define REG_DS 20
|
||||
#define REG_ES 19
|
||||
#define REG_ERR 18
|
||||
#define REG_GS 17
|
||||
#define REG_FS 16
|
||||
#define REG_TRAPNO 15
|
||||
#define REG_RAX 14
|
||||
#define REG_RCX 13
|
||||
#define REG_RDX 12
|
||||
#define REG_RBX 11
|
||||
#define REG_RBP 10
|
||||
#define REG_RSI 9
|
||||
#define REG_RDI 8
|
||||
#define REG_R8 7
|
||||
#define REG_R9 6
|
||||
#define REG_R10 5
|
||||
#define REG_R11 4
|
||||
#define REG_R12 3
|
||||
#define REG_R13 2
|
||||
#define REG_R14 1
|
||||
#define REG_R15 0
|
||||
#endif /* illumos */
|
||||
|
||||
/*
|
||||
* The names and offsets defined here are specified by i386 ABI suppl.
|
||||
*/
|
||||
|
||||
#ifdef illumos
|
||||
#define SS 18 /* only stored on a privilege transition */
|
||||
#define UESP 17 /* only stored on a privilege transition */
|
||||
#define EFL 16
|
||||
#define CS 15
|
||||
#define EIP 14
|
||||
#define ERR 13
|
||||
#define TRAPNO 12
|
||||
#define EAX 11
|
||||
#define ECX 10
|
||||
#define EDX 9
|
||||
#define EBX 8
|
||||
#define ESP 7
|
||||
#define EBP 6
|
||||
#define ESI 5
|
||||
#define EDI 4
|
||||
#define DS 3
|
||||
#define ES 2
|
||||
#define FS 1
|
||||
#define GS 0
|
||||
#else /* !illumos */
|
||||
#define GS 18
|
||||
#define SS 17 /* only stored on a privilege transition */
|
||||
#define UESP 16 /* only stored on a privilege transition */
|
||||
#define EFL 15
|
||||
#define CS 14
|
||||
#define EIP 13
|
||||
#define ERR 12
|
||||
#define TRAPNO 11
|
||||
#define EAX 10
|
||||
#define ECX 9
|
||||
#define EDX 8
|
||||
#define EBX 7
|
||||
#define ESP 6
|
||||
#define EBP 5
|
||||
#define ESI 4
|
||||
#define EDI 3
|
||||
#define DS 2
|
||||
#define ES 1
|
||||
#define FS 0
|
||||
#endif /* illumos */
|
||||
|
||||
#define REG_PC EIP
|
||||
#define REG_FP EBP
|
||||
#define REG_SP UESP
|
||||
#define REG_PS EFL
|
||||
#define REG_R0 EAX
|
||||
#define REG_R1 EDX
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _REGSET_H */
|
|
@ -0,0 +1,403 @@
|
|||
/* $NetBSD: fbt_isa.c,v 1.1 2018/05/28 23:47:39 chs Exp $ */
|
||||
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* 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.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*
|
||||
* Portions Copyright 2006-2008 John Birrell jb@freebsd.org
|
||||
* Portions Copyright 2013 Justin Hibbits jhibbits@freebsd.org
|
||||
* Portions Copyright 2013 Howard Su howardsu@freebsd.org
|
||||
*
|
||||
* $FreeBSD: head/sys/cddl/dev/fbt/arm/fbt_isa.c 312378 2017-01-18 13:27:24Z andrew $
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/kmem.h>
|
||||
|
||||
#include <sys/dtrace.h>
|
||||
|
||||
#include <machine/trap.h>
|
||||
#include <arm/cpufunc.h>
|
||||
#include <arm/armreg.h>
|
||||
#include <arm/frame.h>
|
||||
#include <uvm/uvm_extern.h>
|
||||
|
||||
#include "fbt.h"
|
||||
|
||||
#define FBT_PUSHM 0xe92d0000
|
||||
#define FBT_POPM 0xe8bd0000
|
||||
#define FBT_JUMP 0xea000000
|
||||
#define FBT_SUBSP 0xe24dd000
|
||||
|
||||
#define FBT_ENTRY "entry"
|
||||
#define FBT_RETURN "return"
|
||||
|
||||
int
|
||||
fbt_invop(uintptr_t addr, struct trapframe *frame, uintptr_t rval)
|
||||
{
|
||||
solaris_cpu_t *cpu = &solaris_cpu[cpu_number()];
|
||||
fbt_probe_t *fbt = fbt_probetab[FBT_ADDR2NDX(addr)];
|
||||
register_t fifthparam;
|
||||
|
||||
for (; fbt != NULL; fbt = fbt->fbtp_hashnext) {
|
||||
if ((uintptr_t)fbt->fbtp_patchpoint == addr) {
|
||||
if (fbt->fbtp_roffset == 0) {
|
||||
/* Get 5th parameter from stack */
|
||||
DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
|
||||
fifthparam = *(register_t *)frame->tf_svc_sp;
|
||||
DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT |
|
||||
CPU_DTRACE_BADADDR);
|
||||
|
||||
cpu->cpu_dtrace_caller = frame->tf_svc_lr;
|
||||
dtrace_probe(fbt->fbtp_id, frame->tf_r0,
|
||||
frame->tf_r1, frame->tf_r2,
|
||||
frame->tf_r3, fifthparam);
|
||||
} else {
|
||||
/* XXX set caller */
|
||||
cpu->cpu_dtrace_caller = 0;
|
||||
dtrace_probe(fbt->fbtp_id, fbt->fbtp_roffset,
|
||||
rval, 0, 0, 0);
|
||||
}
|
||||
|
||||
cpu->cpu_dtrace_caller = 0;
|
||||
return (fbt->fbtp_rval);
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
fbt_patch_tracepoint(fbt_probe_t *fbt, fbt_patchval_t val)
|
||||
{
|
||||
dtrace_icookie_t c;
|
||||
|
||||
c = dtrace_interrupt_disable();
|
||||
|
||||
ktext_write(fbt->fbtp_patchpoint, &val, sizeof (val));
|
||||
|
||||
dtrace_interrupt_enable(c);
|
||||
}
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
|
||||
int
|
||||
fbt_provide_module_function(linker_file_t lf, int symindx,
|
||||
linker_symval_t *symval, void *opaque)
|
||||
{
|
||||
char *modname = opaque;
|
||||
const char *name = symval->name;
|
||||
fbt_probe_t *fbt, *retfbt;
|
||||
uint32_t *instr, *limit;
|
||||
int popm;
|
||||
|
||||
if (fbt_excluded(name))
|
||||
return (0);
|
||||
|
||||
instr = (uint32_t *)symval->value;
|
||||
limit = (uint32_t *)(symval->value + symval->size);
|
||||
|
||||
/*
|
||||
* va_arg functions has first instruction of
|
||||
* sub sp, sp, #?
|
||||
*/
|
||||
if ((*instr & 0xfffff000) == FBT_SUBSP)
|
||||
instr++;
|
||||
|
||||
/*
|
||||
* check if insn is a pushm with LR
|
||||
*/
|
||||
if ((*instr & 0xffff0000) != FBT_PUSHM ||
|
||||
(*instr & (1 << LR)) == 0)
|
||||
return (0);
|
||||
|
||||
fbt = kmem_zalloc(sizeof (fbt_probe_t), KM_SLEEP);
|
||||
fbt->fbtp_name = name;
|
||||
fbt->fbtp_id = dtrace_probe_create(fbt_id, modname,
|
||||
name, FBT_ENTRY, 5, fbt);
|
||||
fbt->fbtp_patchpoint = instr;
|
||||
fbt->fbtp_ctl = lf;
|
||||
fbt->fbtp_loadcnt = lf->loadcnt;
|
||||
fbt->fbtp_savedval = *instr;
|
||||
fbt->fbtp_patchval = FBT_BREAKPOINT;
|
||||
fbt->fbtp_rval = DTRACE_INVOP_PUSHM;
|
||||
fbt->fbtp_symindx = symindx;
|
||||
|
||||
fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)];
|
||||
fbt_probetab[FBT_ADDR2NDX(instr)] = fbt;
|
||||
|
||||
lf->fbt_nentries++;
|
||||
|
||||
popm = FBT_POPM | ((*instr) & 0x3FFF) | 0x8000;
|
||||
|
||||
retfbt = NULL;
|
||||
again:
|
||||
for (; instr < limit; instr++) {
|
||||
if (*instr == popm)
|
||||
break;
|
||||
else if ((*instr & 0xff000000) == FBT_JUMP) {
|
||||
uint32_t *target, *start;
|
||||
int offset;
|
||||
|
||||
offset = (*instr & 0xffffff);
|
||||
offset <<= 8;
|
||||
offset /= 64;
|
||||
target = instr + (2 + offset);
|
||||
start = (uint32_t *)symval->value;
|
||||
if (target >= limit || target < start)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (instr >= limit)
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* We have a winner!
|
||||
*/
|
||||
fbt = kmem_zalloc(sizeof (fbt_probe_t), KM_SLEEP);
|
||||
fbt->fbtp_name = name;
|
||||
if (retfbt == NULL) {
|
||||
fbt->fbtp_id = dtrace_probe_create(fbt_id, modname,
|
||||
name, FBT_RETURN, 5, fbt);
|
||||
} else {
|
||||
retfbt->fbtp_next = fbt;
|
||||
fbt->fbtp_id = retfbt->fbtp_id;
|
||||
}
|
||||
retfbt = fbt;
|
||||
|
||||
fbt->fbtp_patchpoint = instr;
|
||||
fbt->fbtp_ctl = lf;
|
||||
fbt->fbtp_loadcnt = lf->loadcnt;
|
||||
fbt->fbtp_symindx = symindx;
|
||||
if ((*instr & 0xff000000) == FBT_JUMP)
|
||||
fbt->fbtp_rval = DTRACE_INVOP_B;
|
||||
else
|
||||
fbt->fbtp_rval = DTRACE_INVOP_POPM;
|
||||
fbt->fbtp_savedval = *instr;
|
||||
fbt->fbtp_patchval = FBT_BREAKPOINT;
|
||||
fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)];
|
||||
fbt_probetab[FBT_ADDR2NDX(instr)] = fbt;
|
||||
|
||||
lf->fbt_nentries++;
|
||||
|
||||
instr++;
|
||||
goto again;
|
||||
}
|
||||
|
||||
#endif /* __FreeBSD_ */
|
||||
|
||||
#ifdef __NetBSD__
|
||||
|
||||
#define FBT_PATCHVAL DTRACE_BREAKPOINT
|
||||
|
||||
/* entry and return */
|
||||
#define FBT_BX_LR_P(insn) (((insn) & ~INSN_COND_MASK) == 0x012fff1e)
|
||||
#define FBT_B_LABEL_P(insn) (((insn) & 0xff000000) == 0xea000000)
|
||||
/* entry */
|
||||
#define FBT_MOV_IP_SP_P(insn) ((insn) == 0xe1a0c00d)
|
||||
/* index=1, add=1, wback=0 */
|
||||
#define FBT_LDR_IMM_P(insn) (((insn) & 0xfff00000) == 0xe5900000)
|
||||
#define FBT_MOVW_P(insn) (((insn) & 0xfff00000) == 0xe3000000)
|
||||
#define FBT_MOV_IMM_P(insn) (((insn) & 0xffff0000) == 0xe3a00000)
|
||||
#define FBT_CMP_IMM_P(insn) (((insn) & 0xfff00000) == 0xe3500000)
|
||||
#define FBT_PUSH_P(insn) (((insn) & 0xffff0000) == 0xe92d0000)
|
||||
/* return */
|
||||
/* cond=always, writeback=no, rn=sp and register_list includes pc */
|
||||
#define FBT_LDM_P(insn) (((insn) & 0x0fff8000) == 0x089d8000)
|
||||
#define FBT_LDMIB_P(insn) (((insn) & 0x0fff8000) == 0x099d8000)
|
||||
#define FBT_MOV_PC_LR_P(insn) (((insn) & ~INSN_COND_MASK) == 0x01a0f00e)
|
||||
/* cond=always, writeback=no, rn=sp and register_list includes lr, but not pc */
|
||||
#define FBT_LDM_LR_P(insn) (((insn) & 0xffffc000) == 0xe89d4000)
|
||||
#define FBT_LDMIB_LR_P(insn) (((insn) & 0xffffc000) == 0xe99d4000)
|
||||
|
||||
/* rval = insn | invop_id (overwriting cond with invop ID) */
|
||||
#define BUILD_RVAL(insn, id) (((insn) & ~INSN_COND_MASK) | __SHIFTIN((id), INSN_COND_MASK))
|
||||
/* encode cond in the first byte */
|
||||
#define PATCHVAL_ENCODE_COND(insn) (FBT_PATCHVAL | __SHIFTOUT((insn), INSN_COND_MASK))
|
||||
|
||||
int
|
||||
fbt_provide_module_cb(const char *name, int symindx, void *value,
|
||||
uint32_t symsize, int type, void *opaque)
|
||||
{
|
||||
fbt_probe_t *fbt, *retfbt;
|
||||
uint32_t *instr, *limit;
|
||||
bool was_ldm_lr = false;
|
||||
int size;
|
||||
|
||||
struct fbt_ksyms_arg *fka = opaque;
|
||||
modctl_t *mod = fka->fka_mod;
|
||||
const char *modname = module_name(mod);
|
||||
|
||||
|
||||
/* got a function? */
|
||||
if (ELF_ST_TYPE(type) != STT_FUNC)
|
||||
return 0;
|
||||
|
||||
if (fbt_excluded(name))
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* Exclude some more symbols which can be called from probe context.
|
||||
*/
|
||||
if (strncmp(name, "_spl", 4) == 0 ||
|
||||
strcmp(name, "binuptime") == 0 ||
|
||||
strcmp(name, "nanouptime") == 0 ||
|
||||
strcmp(name, "dosoftints") == 0 ||
|
||||
strcmp(name, "fbt_emulate") == 0 ||
|
||||
strcmp(name, "undefinedinstruction") == 0 ||
|
||||
strncmp(name, "dmt_", 4) == 0 /* omap */ ||
|
||||
strncmp(name, "mvsoctmr_", 9) == 0 /* marvell */ ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
instr = (uint32_t *) value;
|
||||
limit = (uint32_t *)((uintptr_t)value + symsize);
|
||||
|
||||
if (!FBT_MOV_IP_SP_P(*instr)
|
||||
&& !FBT_BX_LR_P(*instr)
|
||||
&& !FBT_MOVW_P(*instr)
|
||||
&& !FBT_MOV_IMM_P(*instr)
|
||||
&& !FBT_B_LABEL_P(*instr)
|
||||
&& !FBT_LDR_IMM_P(*instr)
|
||||
&& !FBT_CMP_IMM_P(*instr)
|
||||
&& !FBT_PUSH_P(*instr)
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
fbt = kmem_zalloc(sizeof (fbt_probe_t), KM_SLEEP);
|
||||
fbt->fbtp_name = name;
|
||||
fbt->fbtp_id = dtrace_probe_create(fbt_id, modname,
|
||||
name, FBT_ENTRY, 5, fbt);
|
||||
fbt->fbtp_patchpoint = instr;
|
||||
fbt->fbtp_ctl = mod;
|
||||
/* fbt->fbtp_loadcnt = lf->loadcnt; */
|
||||
if (FBT_MOV_IP_SP_P(*instr))
|
||||
fbt->fbtp_rval = BUILD_RVAL(*instr, DTRACE_INVOP_MOV_IP_SP);
|
||||
else if (FBT_LDR_IMM_P(*instr))
|
||||
fbt->fbtp_rval = BUILD_RVAL(*instr, DTRACE_INVOP_LDR_IMM);
|
||||
else if (FBT_MOVW_P(*instr))
|
||||
fbt->fbtp_rval = BUILD_RVAL(*instr, DTRACE_INVOP_MOVW);
|
||||
else if (FBT_MOV_IMM_P(*instr))
|
||||
fbt->fbtp_rval = BUILD_RVAL(*instr, DTRACE_INVOP_MOV_IMM);
|
||||
else if (FBT_CMP_IMM_P(*instr))
|
||||
fbt->fbtp_rval = BUILD_RVAL(*instr, DTRACE_INVOP_CMP_IMM);
|
||||
else if (FBT_BX_LR_P(*instr))
|
||||
fbt->fbtp_rval = BUILD_RVAL(*instr, DTRACE_INVOP_BX_LR);
|
||||
else if (FBT_PUSH_P(*instr))
|
||||
fbt->fbtp_rval = BUILD_RVAL(*instr, DTRACE_INVOP_PUSHM);
|
||||
else if (FBT_B_LABEL_P(*instr))
|
||||
fbt->fbtp_rval = BUILD_RVAL(*instr, DTRACE_INVOP_B);
|
||||
else
|
||||
KASSERT(0);
|
||||
|
||||
KASSERTMSG((fbt->fbtp_rval >> 28) != 0,
|
||||
"fbt %p insn 0x%x name %s rval 0x%08x",
|
||||
fbt, *instr, name, fbt->fbtp_rval);
|
||||
|
||||
fbt->fbtp_patchval = PATCHVAL_ENCODE_COND(*instr);
|
||||
fbt->fbtp_savedval = *instr;
|
||||
fbt->fbtp_symindx = symindx;
|
||||
|
||||
fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)];
|
||||
fbt_probetab[FBT_ADDR2NDX(instr)] = fbt;
|
||||
|
||||
retfbt = NULL;
|
||||
|
||||
while (instr < limit) {
|
||||
if (instr >= limit)
|
||||
return (0);
|
||||
|
||||
size = 1;
|
||||
|
||||
if (!FBT_BX_LR_P(*instr)
|
||||
&& !FBT_MOV_PC_LR_P(*instr)
|
||||
&& !FBT_LDM_P(*instr)
|
||||
&& !FBT_LDMIB_P(*instr)
|
||||
&& !(was_ldm_lr && FBT_B_LABEL_P(*instr))
|
||||
) {
|
||||
if (FBT_LDM_LR_P(*instr) || FBT_LDMIB_LR_P(*instr))
|
||||
was_ldm_lr = true;
|
||||
else
|
||||
was_ldm_lr = false;
|
||||
instr += size;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* We have a winner!
|
||||
*/
|
||||
fbt = kmem_zalloc(sizeof (fbt_probe_t), KM_SLEEP);
|
||||
fbt->fbtp_name = name;
|
||||
|
||||
if (retfbt == NULL) {
|
||||
fbt->fbtp_id = dtrace_probe_create(fbt_id, modname,
|
||||
name, FBT_RETURN, 5, fbt);
|
||||
} else {
|
||||
retfbt->fbtp_next = fbt;
|
||||
fbt->fbtp_id = retfbt->fbtp_id;
|
||||
}
|
||||
|
||||
retfbt = fbt;
|
||||
fbt->fbtp_patchpoint = instr;
|
||||
fbt->fbtp_ctl = mod;
|
||||
/* fbt->fbtp_loadcnt = lf->loadcnt; */
|
||||
fbt->fbtp_symindx = symindx;
|
||||
|
||||
if (FBT_BX_LR_P(*instr))
|
||||
fbt->fbtp_rval = BUILD_RVAL(*instr, DTRACE_INVOP_BX_LR);
|
||||
else if (FBT_MOV_PC_LR_P(*instr))
|
||||
fbt->fbtp_rval = BUILD_RVAL(*instr, DTRACE_INVOP_MOV_PC_LR);
|
||||
else if (FBT_LDM_P(*instr))
|
||||
fbt->fbtp_rval = BUILD_RVAL(*instr, DTRACE_INVOP_LDM);
|
||||
else if (FBT_LDMIB_P(*instr))
|
||||
fbt->fbtp_rval = BUILD_RVAL(*instr, DTRACE_INVOP_POPM);
|
||||
else if (FBT_B_LABEL_P(*instr))
|
||||
fbt->fbtp_rval = BUILD_RVAL(*instr, DTRACE_INVOP_B);
|
||||
else
|
||||
KASSERT(0);
|
||||
|
||||
KASSERTMSG((fbt->fbtp_rval >> 28) != 0, "fbt %p name %s rval 0x%08x",
|
||||
fbt, name, fbt->fbtp_rval);
|
||||
|
||||
fbt->fbtp_roffset = (uintptr_t)(instr - (uint32_t *) value);
|
||||
fbt->fbtp_patchval = PATCHVAL_ENCODE_COND(*instr);
|
||||
|
||||
fbt->fbtp_savedval = *instr;
|
||||
fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)];
|
||||
fbt_probetab[FBT_ADDR2NDX(instr)] = fbt;
|
||||
|
||||
instr += size;
|
||||
was_ldm_lr = false;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* __NetBSD__ */
|
|
@ -0,0 +1,32 @@
|
|||
/* $NetBSD: fbt_isa.h,v 1.1 2018/05/28 23:47:39 chs Exp $ */
|
||||
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* 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.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*
|
||||
* $FreeBSD: head/sys/cddl/dev/fbt/arm/fbt_isa.h 278529 2015-02-10 19:41:30Z gnn $
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _FBT_ISA_H_
|
||||
#define _FBT_ISA_H_
|
||||
|
||||
typedef uint32_t fbt_patchval_t;
|
||||
|
||||
#endif
|
|
@ -0,0 +1,425 @@
|
|||
/* $NetBSD: fbt_isa.c,v 1.1 2018/05/28 23:47:39 chs Exp $ */
|
||||
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* 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.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*
|
||||
* Portions Copyright 2006-2008 John Birrell jb@freebsd.org
|
||||
*
|
||||
* $FreeBSD: head/sys/cddl/dev/fbt/x86/fbt_isa.c 309785 2016-12-10 03:11:05Z markj $
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/cpu.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/kmem.h>
|
||||
|
||||
#include <sys/dtrace.h>
|
||||
|
||||
#if 1
|
||||
#include <machine/cpufunc.h>
|
||||
#include <machine/specialreg.h>
|
||||
#if 0
|
||||
#include <x86/cpuvar.h>
|
||||
#endif
|
||||
#include <x86/cputypes.h>
|
||||
#endif
|
||||
|
||||
#include "fbt.h"
|
||||
|
||||
#define FBT_PUSHL_EBP 0x55
|
||||
#define FBT_MOVL_ESP_EBP0_V0 0x8b
|
||||
#define FBT_MOVL_ESP_EBP1_V0 0xec
|
||||
#define FBT_MOVL_ESP_EBP0_V1 0x89
|
||||
#define FBT_MOVL_ESP_EBP1_V1 0xe5
|
||||
#define FBT_REX_RSP_RBP 0x48
|
||||
|
||||
#define FBT_POPL_EBP 0x5d
|
||||
#define FBT_RET 0xc3
|
||||
#define FBT_RET_IMM16 0xc2
|
||||
#define FBT_LEAVE 0xc9
|
||||
|
||||
#ifdef __amd64__
|
||||
#define FBT_PATCHVAL 0xcc
|
||||
#else
|
||||
#define FBT_PATCHVAL 0xf0
|
||||
#endif
|
||||
|
||||
#define FBT_ENTRY "entry"
|
||||
#define FBT_RETURN "return"
|
||||
|
||||
int
|
||||
fbt_invop(uintptr_t addr, struct trapframe *frame, uintptr_t rval)
|
||||
{
|
||||
solaris_cpu_t *cpu;
|
||||
uintptr_t *stack;
|
||||
uintptr_t arg0, arg1, arg2, arg3, arg4;
|
||||
fbt_probe_t *fbt;
|
||||
|
||||
#ifdef __amd64__
|
||||
stack = (uintptr_t *)frame->tf_rsp;
|
||||
#else
|
||||
/* Skip hardware-saved registers. */
|
||||
#ifdef __NetBSD__
|
||||
stack = (uintptr_t *)&frame->tf_esp;
|
||||
#else
|
||||
stack = (uintptr_t *)frame->tf_isp + 3;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
cpu = &solaris_cpu[cpu_number()];
|
||||
fbt = fbt_probetab[FBT_ADDR2NDX(addr)];
|
||||
for (; fbt != NULL; fbt = fbt->fbtp_hashnext) {
|
||||
if ((uintptr_t)fbt->fbtp_patchpoint == addr) {
|
||||
if (fbt->fbtp_roffset == 0) {
|
||||
#ifdef __amd64__
|
||||
/* fbt->fbtp_rval == DTRACE_INVOP_PUSHQ_RBP */
|
||||
DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
|
||||
cpu->cpu_dtrace_caller = stack[0];
|
||||
DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT |
|
||||
CPU_DTRACE_BADADDR);
|
||||
|
||||
arg0 = frame->tf_rdi;
|
||||
arg1 = frame->tf_rsi;
|
||||
arg2 = frame->tf_rdx;
|
||||
arg3 = frame->tf_rcx;
|
||||
arg4 = frame->tf_r8;
|
||||
#else
|
||||
int i = 0;
|
||||
|
||||
/*
|
||||
* When accessing the arguments on the stack,
|
||||
* we must protect against accessing beyond
|
||||
* the stack. We can safely set NOFAULT here
|
||||
* -- we know that interrupts are already
|
||||
* disabled.
|
||||
*/
|
||||
DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
|
||||
cpu->cpu_dtrace_caller = stack[i++];
|
||||
arg0 = stack[i++];
|
||||
arg1 = stack[i++];
|
||||
arg2 = stack[i++];
|
||||
arg3 = stack[i++];
|
||||
arg4 = stack[i++];
|
||||
DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT |
|
||||
CPU_DTRACE_BADADDR);
|
||||
#endif
|
||||
|
||||
dtrace_probe(fbt->fbtp_id, arg0, arg1,
|
||||
arg2, arg3, arg4);
|
||||
|
||||
cpu->cpu_dtrace_caller = 0;
|
||||
} else {
|
||||
#ifdef __amd64__
|
||||
/*
|
||||
* On amd64, we instrument the ret, not the
|
||||
* leave. We therefore need to set the caller
|
||||
* to ensure that the top frame of a stack()
|
||||
* action is correct.
|
||||
*/
|
||||
DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
|
||||
cpu->cpu_dtrace_caller = stack[0];
|
||||
DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT |
|
||||
CPU_DTRACE_BADADDR);
|
||||
#endif
|
||||
|
||||
dtrace_probe(fbt->fbtp_id, fbt->fbtp_roffset,
|
||||
rval, 0, 0, 0);
|
||||
cpu->cpu_dtrace_caller = 0;
|
||||
}
|
||||
|
||||
return (fbt->fbtp_rval);
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
void
|
||||
fbt_patch_tracepoint(fbt_probe_t *fbt, fbt_patchval_t val)
|
||||
{
|
||||
|
||||
*fbt->fbtp_patchpoint = val;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __NetBSD__
|
||||
void
|
||||
fbt_patch_tracepoint(fbt_probe_t *fbt, fbt_patchval_t val)
|
||||
{
|
||||
u_long psl;
|
||||
u_long cr0;
|
||||
|
||||
/* Disable interrupts. */
|
||||
psl = x86_read_psl();
|
||||
x86_disable_intr();
|
||||
|
||||
/* Disable write protection in supervisor mode. */
|
||||
cr0 = rcr0();
|
||||
lcr0(cr0 & ~CR0_WP);
|
||||
|
||||
for (; fbt != NULL; fbt = fbt->fbtp_next) {
|
||||
*fbt->fbtp_patchpoint = val;
|
||||
}
|
||||
|
||||
/* Write back and invalidate cache, flush pipelines. */
|
||||
wbinvd();
|
||||
x86_flush();
|
||||
x86_write_psl(psl);
|
||||
|
||||
/* Re-enable write protection. */
|
||||
lcr0(cr0);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
int
|
||||
fbt_provide_module_function(linker_file_t lf, int symindx,
|
||||
linker_symval_t *symval, void *opaque)
|
||||
#endif
|
||||
#ifdef __NetBSD__
|
||||
int
|
||||
fbt_provide_module_cb(const char *name, int symindx, void *value,
|
||||
uint32_t symsize, int type, void *opaque)
|
||||
#endif
|
||||
{
|
||||
fbt_probe_t *fbt, *retfbt;
|
||||
u_int8_t *instr, *limit;
|
||||
int j;
|
||||
int size;
|
||||
|
||||
#ifdef __FreeBSD_
|
||||
char *modname = opaque;
|
||||
const char *name = symval->name;
|
||||
size_t symsize = symval->size;
|
||||
void *value = symval->value;
|
||||
|
||||
/*
|
||||
* trap_check() is a wrapper for DTrace's fault handler, so we don't
|
||||
* want to be able to instrument it.
|
||||
*/
|
||||
if (strcmp(name, "trap_check") == 0)
|
||||
return (0);
|
||||
#endif
|
||||
#ifdef __NetBSD__
|
||||
struct fbt_ksyms_arg *fka = opaque;
|
||||
modctl_t *mod = fka->fka_mod;
|
||||
const char *modname = module_name(mod);
|
||||
|
||||
/* got a function? */
|
||||
if (ELF_ST_TYPE(type) != STT_FUNC)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Exclude some more symbols which can be called from probe context.
|
||||
*/
|
||||
if (strcmp(name, "x86_curcpu") == 0 ||
|
||||
strcmp(name, "x86_curlwp") == 0) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (fbt_excluded(name))
|
||||
return (0);
|
||||
|
||||
instr = (u_int8_t *) value;
|
||||
limit = (u_int8_t *) value + symsize;
|
||||
|
||||
#ifdef __amd64__
|
||||
while (instr < limit) {
|
||||
if (*instr == FBT_PUSHL_EBP)
|
||||
break;
|
||||
|
||||
if ((size = dtrace_instr_size(instr)) <= 0)
|
||||
break;
|
||||
|
||||
instr += size;
|
||||
}
|
||||
|
||||
if (instr >= limit || *instr != FBT_PUSHL_EBP) {
|
||||
/*
|
||||
* We either don't save the frame pointer in this
|
||||
* function, or we ran into some disassembly
|
||||
* screw-up. Either way, we bail.
|
||||
*/
|
||||
return (0);
|
||||
}
|
||||
#else
|
||||
if (instr[0] != FBT_PUSHL_EBP)
|
||||
return (0);
|
||||
|
||||
if (!(instr[1] == FBT_MOVL_ESP_EBP0_V0 &&
|
||||
instr[2] == FBT_MOVL_ESP_EBP1_V0) &&
|
||||
!(instr[1] == FBT_MOVL_ESP_EBP0_V1 &&
|
||||
instr[2] == FBT_MOVL_ESP_EBP1_V1))
|
||||
return (0);
|
||||
#endif
|
||||
|
||||
fbt = kmem_zalloc(sizeof (*fbt), KM_SLEEP);
|
||||
fbt->fbtp_name = name;
|
||||
fbt->fbtp_id = dtrace_probe_create(fbt_id, modname,
|
||||
name, FBT_ENTRY, 3, fbt);
|
||||
fbt->fbtp_patchpoint = instr;
|
||||
#ifdef __FreeBSD__
|
||||
fbt->fbtp_ctl = lf;
|
||||
fbt->fbtp_loadcnt = lf->loadcnt;
|
||||
#endif
|
||||
#ifdef __NetBSD__
|
||||
fbt->fbtp_ctl = mod;
|
||||
#endif
|
||||
fbt->fbtp_rval = DTRACE_INVOP_PUSHL_EBP;
|
||||
fbt->fbtp_savedval = *instr;
|
||||
fbt->fbtp_patchval = FBT_PATCHVAL;
|
||||
fbt->fbtp_symindx = symindx;
|
||||
|
||||
fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)];
|
||||
fbt_probetab[FBT_ADDR2NDX(instr)] = fbt;
|
||||
#ifdef __FreeBSD__
|
||||
lf->fbt_nentries++;
|
||||
#endif
|
||||
|
||||
retfbt = NULL;
|
||||
again:
|
||||
if (instr >= limit)
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* If this disassembly fails, then we've likely walked off into
|
||||
* a jump table or some other unsuitable area. Bail out of the
|
||||
* disassembly now.
|
||||
*/
|
||||
if ((size = dtrace_instr_size(instr)) <= 0)
|
||||
return (0);
|
||||
|
||||
#ifdef __amd64__
|
||||
/*
|
||||
* We only instrument "ret" on amd64 -- we don't yet instrument
|
||||
* ret imm16, largely because the compiler doesn't seem to
|
||||
* (yet) emit them in the kernel...
|
||||
*/
|
||||
if (*instr != FBT_RET) {
|
||||
instr += size;
|
||||
goto again;
|
||||
}
|
||||
#else
|
||||
if (!(size == 1 &&
|
||||
(*instr == FBT_POPL_EBP || *instr == FBT_LEAVE) &&
|
||||
(*(instr + 1) == FBT_RET ||
|
||||
*(instr + 1) == FBT_RET_IMM16))) {
|
||||
instr += size;
|
||||
goto again;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* We (desperately) want to avoid erroneously instrumenting a
|
||||
* jump table, especially given that our markers are pretty
|
||||
* short: two bytes on x86, and just one byte on amd64. To
|
||||
* determine if we're looking at a true instruction sequence
|
||||
* or an inline jump table that happens to contain the same
|
||||
* byte sequences, we resort to some heuristic sleeze: we
|
||||
* treat this instruction as being contained within a pointer,
|
||||
* and see if that pointer points to within the body of the
|
||||
* function. If it does, we refuse to instrument it.
|
||||
*/
|
||||
for (j = 0; j < sizeof (uintptr_t); j++) {
|
||||
caddr_t check = (caddr_t) instr - j;
|
||||
uint8_t *ptr;
|
||||
|
||||
if (check < (caddr_t)value)
|
||||
break;
|
||||
|
||||
if (check + sizeof (caddr_t) > (caddr_t)limit)
|
||||
continue;
|
||||
|
||||
ptr = *(uint8_t **)check;
|
||||
|
||||
if (ptr >= (uint8_t *) value && ptr < limit) {
|
||||
instr += size;
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We have a winner!
|
||||
*/
|
||||
fbt = kmem_zalloc(sizeof (*fbt), KM_SLEEP);
|
||||
fbt->fbtp_name = name;
|
||||
|
||||
if (retfbt == NULL) {
|
||||
fbt->fbtp_id = dtrace_probe_create(fbt_id, modname,
|
||||
name, FBT_RETURN, 3, fbt);
|
||||
} else {
|
||||
retfbt->fbtp_next = fbt;
|
||||
fbt->fbtp_id = retfbt->fbtp_id;
|
||||
}
|
||||
|
||||
retfbt = fbt;
|
||||
fbt->fbtp_patchpoint = instr;
|
||||
#ifdef __FreeBSD__
|
||||
fbt->fbtp_ctl = lf;
|
||||
fbt->fbtp_loadcnt = lf->loadcnt;
|
||||
#endif
|
||||
#ifdef __NetBSD__
|
||||
fbt->fbtp_ctl = mod;
|
||||
#endif
|
||||
fbt->fbtp_symindx = symindx;
|
||||
|
||||
#ifndef __amd64__
|
||||
if (*instr == FBT_POPL_EBP) {
|
||||
fbt->fbtp_rval = DTRACE_INVOP_POPL_EBP;
|
||||
} else {
|
||||
ASSERT(*instr == FBT_LEAVE);
|
||||
fbt->fbtp_rval = DTRACE_INVOP_LEAVE;
|
||||
}
|
||||
fbt->fbtp_roffset =
|
||||
(uintptr_t)(instr - (uint8_t *) value) + 1;
|
||||
|
||||
#else
|
||||
ASSERT(*instr == FBT_RET);
|
||||
fbt->fbtp_rval = DTRACE_INVOP_RET;
|
||||
fbt->fbtp_roffset =
|
||||
(uintptr_t)(instr - (uint8_t *) value);
|
||||
#endif
|
||||
|
||||
fbt->fbtp_savedval = *instr;
|
||||
fbt->fbtp_patchval = FBT_PATCHVAL;
|
||||
fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)];
|
||||
fbt_probetab[FBT_ADDR2NDX(instr)] = fbt;
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
lf->fbt_nentries++;
|
||||
#endif
|
||||
|
||||
instr += size;
|
||||
goto again;
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/* $NetBSD: fbt_isa.h,v 1.1 2018/05/28 23:47:40 chs Exp $ */
|
||||
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* 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.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*
|
||||
* $FreeBSD: head/sys/cddl/dev/fbt/x86/fbt_isa.h 270067 2014-08-16 21:42:55Z markj $
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _FBT_ISA_H_
|
||||
#define _FBT_ISA_H_
|
||||
|
||||
typedef uint8_t fbt_patchval_t;
|
||||
|
||||
#endif
|
|
@ -0,0 +1,24 @@
|
|||
# $NetBSD: Makefile,v 1.1 2018/05/28 23:47:40 chs Exp $
|
||||
|
||||
.include <bsd.init.mk>
|
||||
|
||||
.PATH: ${.CURDIR}/../../dist/common/zfs
|
||||
.PATH: ${.CURDIR}/../../dist/common/fs/zfs
|
||||
.PATH: ${.CURDIR}/../../dist/lib/libzfs/common
|
||||
.PATH: ${.CURDIR}/../../dist/lib/libzfs_core/common
|
||||
|
||||
LIB= zfs_core
|
||||
|
||||
LIBDPLIBS+= \
|
||||
nvpair ${.CURDIR}/../libnvpair
|
||||
|
||||
|
||||
SRCS= libzfs_core.c \
|
||||
libzfs_core_compat.c \
|
||||
zfs_ioctl_compat.c
|
||||
|
||||
SRCS+= libzfs_compat.c
|
||||
|
||||
.include "../../Makefile.zfs"
|
||||
.include <bsd.lib.mk>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
# $NetBSD: shlib_version,v 1.1 2018/05/28 23:47:40 chs Exp $
|
||||
# Remember to update distrib/sets/lists/base/shl.* when changing
|
||||
|
||||
major=0
|
||||
minor=0
|
Loading…
Reference in New Issue