Handle functions that use a nop in the arm64 fbt

To trace leaf asm functions we can insert a single nop instruction as
the first instruction in a function and trigger off this.

Reviewed by:	gnn
Sponsored by:	Innovate UK
Differential Revision:	https://reviews.freebsd.org/D28132
This commit is contained in:
Andrew Turner 2021-01-13 11:08:19 +00:00
parent 48ba9b2669
commit 28d945204e
4 changed files with 46 additions and 20 deletions

View File

@ -38,9 +38,15 @@
#define _C_LABEL(x) x
#ifdef KDTRACE_HOOKS
#define DTRACE_NOP nop
#else
#define DTRACE_NOP
#endif
#define LENTRY(sym) \
.text; .align 2; .type sym,#function; sym: \
.cfi_startproc
.cfi_startproc; DTRACE_NOP
#define ENTRY(sym) \
.globl sym; LENTRY(sym)
#define EENTRY(sym) \

View File

@ -2466,6 +2466,8 @@ extern void dtrace_helpers_destroy(proc_t *);
#define B_DATA_MASK 0x00ffffff
#define B_INSTR 0x14000000
#define NOP_INSTR 0xd503201f
#define RET_INSTR 0xd65f03c0
#define SUB_MASK 0xffc00000

View File

@ -314,6 +314,11 @@ dtrace_invop_start(struct trapframe *frame)
return (0);
}
if (invop == NOP_INSTR) {
frame->tf_elr += INSN_SIZE;
return (0);
}
if ((invop & B_MASK) == B_INSTR) {
data = (invop & B_DATA_MASK);
/* The data is the number of 4-byte words to change the pc */

View File

@ -110,28 +110,41 @@ fbt_provide_module_function(linker_file_t lf, int symindx,
/* Look for stp (pre-indexed) operation */
found = false;
for (; instr < limit; instr++) {
/* Some functions start with "stp xt1, xt2, [xn, <const>]!" */
if ((*instr & LDP_STP_MASK) == STP_64) {
/*
* If the first instruction is a nop it's a specially marked
* asm function. We only support a nop first as it's not a normal
* part of the function prologue.
*/
if (*instr == NOP_INSTR)
found = true;
if (!found) {
for (; instr < limit; instr++) {
/*
* Assume any other store of this type means we
* are past the function prolog.
* Some functions start with
* "stp xt1, xt2, [xn, <const>]!"
*/
if (((*instr >> ADDR_SHIFT) & ADDR_MASK) == 31)
found = true;
break;
}
if ((*instr & LDP_STP_MASK) == STP_64) {
/*
* Assume any other store of this type means we
* are past the function prolog.
*/
if (((*instr >> ADDR_SHIFT) & ADDR_MASK) == 31)
found = true;
break;
}
/*
* Some functions start with a "sub sp, sp, <const>"
* Sometimes the compiler will have a sub instruction that
* is not of the above type so don't stop if we see one.
*/
if ((*instr & SUB_MASK) == SUB_INSTR &&
((*instr >> SUB_RD_SHIFT) & SUB_R_MASK) == 31 &&
((*instr >> SUB_RN_SHIFT) & SUB_R_MASK) == 31) {
found = true;
break;
/*
* Some functions start with a "sub sp, sp, <const>"
* Sometimes the compiler will have a sub instruction
* that is not of the above type so don't stop if we
* see one.
*/
if ((*instr & SUB_MASK) == SUB_INSTR &&
((*instr >> SUB_RD_SHIFT) & SUB_R_MASK) == 31 &&
((*instr >> SUB_RN_SHIFT) & SUB_R_MASK) == 31) {
found = true;
break;
}
}
}