mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 22:21:40 +00:00
ftrace: use nops instead of jmp
This patch patches the call to mcount with nops instead of a jmp over the mcount call. Signed-off-by: Steven Rostedt <srostedt@redhat.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
This commit is contained in:
parent
b0fc494fae
commit
dfa60aba04
@ -143,7 +143,7 @@ static const unsigned char *const p6_nops[ASM_NOP_MAX+1] = {
|
|||||||
#ifdef CONFIG_X86_64
|
#ifdef CONFIG_X86_64
|
||||||
|
|
||||||
extern char __vsyscall_0;
|
extern char __vsyscall_0;
|
||||||
static inline const unsigned char*const * find_nop_table(void)
|
const unsigned char *const *find_nop_table(void)
|
||||||
{
|
{
|
||||||
return boot_cpu_data.x86_vendor != X86_VENDOR_INTEL ||
|
return boot_cpu_data.x86_vendor != X86_VENDOR_INTEL ||
|
||||||
boot_cpu_data.x86 < 6 ? k8_nops : p6_nops;
|
boot_cpu_data.x86 < 6 ? k8_nops : p6_nops;
|
||||||
@ -162,7 +162,7 @@ static const struct nop {
|
|||||||
{ -1, NULL }
|
{ -1, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
static const unsigned char*const * find_nop_table(void)
|
const unsigned char *const *find_nop_table(void)
|
||||||
{
|
{
|
||||||
const unsigned char *const *noptable = intel_nops;
|
const unsigned char *const *noptable = intel_nops;
|
||||||
int i;
|
int i;
|
||||||
|
@ -16,11 +16,12 @@
|
|||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
|
|
||||||
|
#include <asm/alternative.h>
|
||||||
|
|
||||||
#define CALL_BACK 5
|
#define CALL_BACK 5
|
||||||
|
|
||||||
#define JMPFWD 0x03eb
|
/* Long is fine, even if it is only 4 bytes ;-) */
|
||||||
|
static long *ftrace_nop;
|
||||||
static unsigned short ftrace_jmp = JMPFWD;
|
|
||||||
|
|
||||||
struct ftrace_record {
|
struct ftrace_record {
|
||||||
struct dyn_ftrace rec;
|
struct dyn_ftrace rec;
|
||||||
@ -55,13 +56,13 @@ static struct ftrace_page *ftrace_pages;
|
|||||||
notrace struct dyn_ftrace *ftrace_alloc_shutdown_node(unsigned long ip)
|
notrace struct dyn_ftrace *ftrace_alloc_shutdown_node(unsigned long ip)
|
||||||
{
|
{
|
||||||
struct ftrace_record *rec;
|
struct ftrace_record *rec;
|
||||||
unsigned short save;
|
unsigned long save;
|
||||||
|
|
||||||
ip -= CALL_BACK;
|
ip -= CALL_BACK;
|
||||||
save = *(short *)ip;
|
save = *(long *)ip;
|
||||||
|
|
||||||
/* If this was already converted, skip it */
|
/* If this was already converted, skip it */
|
||||||
if (save == JMPFWD)
|
if (save == *ftrace_nop)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (ftrace_pages->index == ENTRIES_PER_PAGE) {
|
if (ftrace_pages->index == ENTRIES_PER_PAGE) {
|
||||||
@ -79,9 +80,10 @@ static int notrace
|
|||||||
ftrace_modify_code(unsigned long ip, unsigned char *old_code,
|
ftrace_modify_code(unsigned long ip, unsigned char *old_code,
|
||||||
unsigned char *new_code)
|
unsigned char *new_code)
|
||||||
{
|
{
|
||||||
unsigned short old = *(unsigned short *)old_code;
|
unsigned replaced;
|
||||||
unsigned short new = *(unsigned short *)new_code;
|
unsigned old = *(unsigned *)old_code; /* 4 bytes */
|
||||||
unsigned short replaced;
|
unsigned new = *(unsigned *)new_code; /* 4 bytes */
|
||||||
|
unsigned char newch = new_code[4];
|
||||||
int faulted = 0;
|
int faulted = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -94,7 +96,9 @@ ftrace_modify_code(unsigned long ip, unsigned char *old_code,
|
|||||||
*/
|
*/
|
||||||
asm volatile (
|
asm volatile (
|
||||||
"1: lock\n"
|
"1: lock\n"
|
||||||
" cmpxchg %w3, (%2)\n"
|
" cmpxchg %3, (%2)\n"
|
||||||
|
" jnz 2f\n"
|
||||||
|
" movb %b4, 4(%2)\n"
|
||||||
"2:\n"
|
"2:\n"
|
||||||
".section .fixup, \"ax\"\n"
|
".section .fixup, \"ax\"\n"
|
||||||
" movl $1, %0\n"
|
" movl $1, %0\n"
|
||||||
@ -102,11 +106,12 @@ ftrace_modify_code(unsigned long ip, unsigned char *old_code,
|
|||||||
".previous\n"
|
".previous\n"
|
||||||
_ASM_EXTABLE(1b, 3b)
|
_ASM_EXTABLE(1b, 3b)
|
||||||
: "=r"(faulted), "=a"(replaced)
|
: "=r"(faulted), "=a"(replaced)
|
||||||
: "r"(ip), "r"(new), "0"(faulted), "a"(old)
|
: "r"(ip), "r"(new), "r"(newch),
|
||||||
|
"0"(faulted), "a"(old)
|
||||||
: "memory");
|
: "memory");
|
||||||
sync_core();
|
sync_core();
|
||||||
|
|
||||||
if (replaced != old)
|
if (replaced != old && replaced != new)
|
||||||
faulted = 2;
|
faulted = 2;
|
||||||
|
|
||||||
return faulted;
|
return faulted;
|
||||||
@ -132,7 +137,7 @@ notrace void ftrace_code_disable(struct dyn_ftrace *rec)
|
|||||||
/* move the IP back to the start of the call */
|
/* move the IP back to the start of the call */
|
||||||
ip -= CALL_BACK;
|
ip -= CALL_BACK;
|
||||||
|
|
||||||
r->failed = ftrace_modify_code(ip, save.code, (char *)&ftrace_jmp);
|
r->failed = ftrace_modify_code(ip, save.code, (char *)ftrace_nop);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void notrace ftrace_replace_code(int saved)
|
static void notrace ftrace_replace_code(int saved)
|
||||||
@ -144,9 +149,9 @@ static void notrace ftrace_replace_code(int saved)
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (saved)
|
if (saved)
|
||||||
old = (char *)&ftrace_jmp;
|
old = (char *)ftrace_nop;
|
||||||
else
|
else
|
||||||
new = (char *)&ftrace_jmp;
|
new = (char *)ftrace_nop;
|
||||||
|
|
||||||
for (pg = ftrace_pages_start; pg; pg = pg->next) {
|
for (pg = ftrace_pages_start; pg; pg = pg->next) {
|
||||||
for (i = 0; i < pg->index; i++) {
|
for (i = 0; i < pg->index; i++) {
|
||||||
@ -194,12 +199,15 @@ notrace void ftrace_shutdown_replenish(void)
|
|||||||
ftrace_pages->next = (void *)get_zeroed_page(GFP_KERNEL);
|
ftrace_pages->next = (void *)get_zeroed_page(GFP_KERNEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
notrace int ftrace_shutdown_arch_init(void)
|
notrace int __init ftrace_shutdown_arch_init(void)
|
||||||
{
|
{
|
||||||
|
const unsigned char *const *noptable = find_nop_table();
|
||||||
struct ftrace_page *pg;
|
struct ftrace_page *pg;
|
||||||
int cnt;
|
int cnt;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
ftrace_nop = (unsigned long *)noptable[CALL_BACK];
|
||||||
|
|
||||||
/* allocate a few pages */
|
/* allocate a few pages */
|
||||||
ftrace_pages_start = (void *)get_zeroed_page(GFP_KERNEL);
|
ftrace_pages_start = (void *)get_zeroed_page(GFP_KERNEL);
|
||||||
if (!ftrace_pages_start)
|
if (!ftrace_pages_start)
|
||||||
|
@ -72,6 +72,8 @@ static inline void alternatives_smp_module_del(struct module *mod) {}
|
|||||||
static inline void alternatives_smp_switch(int smp) {}
|
static inline void alternatives_smp_switch(int smp) {}
|
||||||
#endif /* CONFIG_SMP */
|
#endif /* CONFIG_SMP */
|
||||||
|
|
||||||
|
const unsigned char *const *find_nop_table(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Alternative instructions for different CPU types or capabilities.
|
* Alternative instructions for different CPU types or capabilities.
|
||||||
*
|
*
|
||||||
|
Loading…
Reference in New Issue
Block a user