History

ftrace: Add ftrace_find_direct_func()

As function_graph tracer modifies the return address to insert a trampoline to trace the return of a function, it must be aware of a direct caller, as when it gets called, the function's return address may not be at on the stack where it expects. It may have to see if that return address points to the a direct caller and adjust if it is.

Steven Rostedt (VMware) committed 7 years ago

Commit 013bf0d1 parent 763e34e2 files · +84 −1Browse files

Unified · Split

2 files
  1. include/linux/ftrace.h +6 −0
  2. kernel/trace/ftrace.c +78 −1
include/linux/ftrace.h+6−0
@@ -51,6 +51,7 @@ static inline void early_trace_init(void) { } · 50 unmodified lines
51 51
52struct module;52struct module;
53struct ftrace_hash;53struct ftrace_hash;
54struct ftrace_direct_func;
54 55
55#if defined(CONFIG_FUNCTION_TRACER) && defined(CONFIG_MODULES) && \56#if defined(CONFIG_FUNCTION_TRACER) && defined(CONFIG_MODULES) && \
56 defined(CONFIG_DYNAMIC_FTRACE)57 defined(CONFIG_DYNAMIC_FTRACE)
@@ -248,6 +249,7 @@ static inline void ftrace_free_mem(struct module *mod, void *start, void *end) { · 191 unmodified lines
248#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS249#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
249int register_ftrace_direct(unsigned long ip, unsigned long addr);250int register_ftrace_direct(unsigned long ip, unsigned long addr);
250int unregister_ftrace_direct(unsigned long ip, unsigned long addr);251int unregister_ftrace_direct(unsigned long ip, unsigned long addr);
252struct ftrace_direct_func *ftrace_find_direct_func(unsigned long addr);
251#else253#else
252static inline int register_ftrace_direct(unsigned long ip, unsigned long addr)254static inline int register_ftrace_direct(unsigned long ip, unsigned long addr)
253{255{
@@ -257,6 +259,10 @@ static inline int unregister_ftrace_direct(unsigned long ip, unsigned long addr) · 3 unmodified lines
257{259{
258 return -ENODEV;260 return -ENODEV;
259}261}
262static inline struct ftrace_direct_func *ftrace_find_direct_func(unsigned long addr)
263{
264 return NULL;
265}
260#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */266#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
261 267
262#ifndef CONFIG_HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS268#ifndef CONFIG_HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
kernel/trace/ftrace.c+78−1
@@ -4938,6 +4938,46 @@ ftrace_set_addr(struct ftrace_ops *ops, unsigned long ip, int remove, · 4937 unmodified lines
4938}4938}
4939 4939
4940#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS4940#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
4941
4942struct ftrace_direct_func {
4943 struct list_head next;
4944 unsigned long addr;
4945 int count;
4946};
4947
4948static LIST_HEAD(ftrace_direct_funcs);
4949
4950/**
4951 * ftrace_find_direct_func - test an address if it is a registered direct caller
4952 * @addr: The address of a registered direct caller
4953 *
4954 * This searches to see if a ftrace direct caller has been registered
4955 * at a specific address, and if so, it returns a descriptor for it.
4956 *
4957 * This can be used by architecture code to see if an address is
4958 * a direct caller (trampoline) attached to a fentry/mcount location.
4959 * This is useful for the function_graph tracer, as it may need to
4960 * do adjustments if it traced a location that also has a direct
4961 * trampoline attached to it.
4962 */
4963struct ftrace_direct_func *ftrace_find_direct_func(unsigned long addr)
4964{
4965 struct ftrace_direct_func *entry;
4966 bool found = false;
4967
4968 /* May be called by fgraph trampoline (protected by rcu tasks) */
4969 list_for_each_entry_rcu(entry, &ftrace_direct_funcs, next) {
4970 if (entry->addr == addr) {
4971 found = true;
4972 break;
4973 }
4974 }
4975 if (found)
4976 return entry;
4977
4978 return NULL;
4979}
4980
4941/**4981/**
4942 * register_ftrace_direct - Call a custom trampoline directly4982 * register_ftrace_direct - Call a custom trampoline directly
4943 * @ip: The address of the nop at the beginning of a function4983 * @ip: The address of the nop at the beginning of a function
@@ -4957,6 +4997,7 @@ ftrace_set_addr(struct ftrace_ops *ops, unsigned long ip, int remove, · 13 unmodified lines
4957 */4997 */
4958int register_ftrace_direct(unsigned long ip, unsigned long addr)4998int register_ftrace_direct(unsigned long ip, unsigned long addr)
4959{4999{
5000 struct ftrace_direct_func *direct;
4960 struct ftrace_func_entry *entry;5001 struct ftrace_func_entry *entry;
4961 struct ftrace_hash *free_hash = NULL;5002 struct ftrace_hash *free_hash = NULL;
4962 struct dyn_ftrace *rec;5003 struct dyn_ftrace *rec;
@@ -5005,6 +5046,18 @@ int register_ftrace_direct(unsigned long ip, unsigned long addr) · 42 unmodified lines
5005 if (!entry)5046 if (!entry)
5006 goto out_unlock;5047 goto out_unlock;
5007 5048
5049 direct = ftrace_find_direct_func(addr);
5050 if (!direct) {
5051 direct = kmalloc(sizeof(*direct), GFP_KERNEL);
5052 if (!direct) {
5053 kfree(entry);
5054 goto out_unlock;
5055 }
5056 direct->addr = addr;
5057 direct->count = 0;
5058 list_add_rcu(&direct->next, &ftrace_direct_funcs);
5059 }
5060
5008 entry->ip = ip;5061 entry->ip = ip;
5009 entry->direct = addr;5062 entry->direct = addr;
5010 __add_hash_entry(direct_functions, entry);5063 __add_hash_entry(direct_functions, entry);
@@ -5019,8 +5072,20 @@ int register_ftrace_direct(unsigned long ip, unsigned long addr) · 8 unmodified lines
5019 ftrace_set_filter_ip(&direct_ops, ip, 1, 0);5072 ftrace_set_filter_ip(&direct_ops, ip, 1, 0);
5020 }5073 }
5021 5074
5022 if (ret)5075 if (ret) {
5023 kfree(entry);5076 kfree(entry);
5077 if (!direct->count) {
5078 list_del_rcu(&direct->next);
5079 synchronize_rcu_tasks();
5080 kfree(direct);
5081 if (free_hash)
5082 free_ftrace_hash(free_hash);
5083 free_hash = NULL;
5084 }
5085 } else {
5086 if (!direct->count)
5087 direct->count++;
5088 }
5024 out_unlock:5089 out_unlock:
5025 mutex_unlock(&direct_mutex);5090 mutex_unlock(&direct_mutex);
5026 5091
@@ -5036,6 +5101,7 @@ EXPORT_SYMBOL_GPL(register_ftrace_direct); · 9 unmodified lines
5036int unregister_ftrace_direct(unsigned long ip, unsigned long addr)5101int unregister_ftrace_direct(unsigned long ip, unsigned long addr)
5037{5102{
5038 struct ftrace_func_entry *entry;5103 struct ftrace_func_entry *entry;
5104 struct ftrace_direct_func *direct;
5039 struct dyn_ftrace *rec;5105 struct dyn_ftrace *rec;
5040 int ret = -ENODEV;5106 int ret = -ENODEV;
5041 5107
@@ -5066,6 +5132,17 @@ int unregister_ftrace_direct(unsigned long ip, unsigned long addr) · 24 unmodified lines
5066 5132
5067 remove_hash_entry(direct_functions, entry);5133 remove_hash_entry(direct_functions, entry);
5068 5134
5135 direct = ftrace_find_direct_func(addr);
5136 if (!WARN_ON(!direct)) {
5137 /* This is the good path (see the ! before WARN) */
5138 direct->count--;
5139 WARN_ON(direct->count < 0);
5140 if (!direct->count) {
5141 list_del_rcu(&direct->next);
5142 synchronize_rcu_tasks();
5143 kfree(direct);
5144 }
5145 }
5069 out_unlock:5146 out_unlock:
5070 mutex_unlock(&direct_mutex);5147 mutex_unlock(&direct_mutex);
5071 5148

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t