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
5151
5252 struct module;
5353 struct ftrace_hash;
54+struct ftrace_direct_func;
5455
5556 #if defined(CONFIG_FUNCTION_TRACER) && defined(CONFIG_MODULES) && \
5657 defined(CONFIG_DYNAMIC_FTRACE)
@@ -248,6 +249,7 @@ static inline void ftrace_free_mem(struct module *mod, void *start, void *end) { · 191 unmodified lines
248249 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
249250 int register_ftrace_direct(unsigned long ip, unsigned long addr);
250251 int unregister_ftrace_direct(unsigned long ip, unsigned long addr);
252+struct ftrace_direct_func *ftrace_find_direct_func(unsigned long addr);
251253 #else
252254 static inline int register_ftrace_direct(unsigned long ip, unsigned long addr)
253255 {
@@ -257,6 +259,10 @@ static inline int unregister_ftrace_direct(unsigned long ip, unsigned long addr) · 3 unmodified lines
257259 {
258260 return -ENODEV;
259261 }
262+static inline struct ftrace_direct_func *ftrace_find_direct_func(unsigned long addr)
263+{
264+ return NULL;
265+}
260266 #endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
261267
262268 #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
49384938 }
49394939
49404940 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
4941+
4942+struct ftrace_direct_func {
4943+ struct list_head next;
4944+ unsigned long addr;
4945+ int count;
4946+};
4947+
4948+static 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+ */
4963+struct 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+
49414981 /**
49424982 * register_ftrace_direct - Call a custom trampoline directly
49434983 * @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
49574997 */
49584998 int register_ftrace_direct(unsigned long ip, unsigned long addr)
49594999 {
5000+ struct ftrace_direct_func *direct;
49605001 struct ftrace_func_entry *entry;
49615002 struct ftrace_hash *free_hash = NULL;
49625003 struct dyn_ftrace *rec;
@@ -5005,6 +5046,18 @@ int register_ftrace_direct(unsigned long ip, unsigned long addr) · 42 unmodified lines
50055046 if (!entry)
50065047 goto out_unlock;
50075048
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+
50085061 entry->ip = ip;
50095062 entry->direct = addr;
50105063 __add_hash_entry(direct_functions, entry);
@@ -5019,8 +5072,20 @@ int register_ftrace_direct(unsigned long ip, unsigned long addr) · 8 unmodified lines
50195072 ftrace_set_filter_ip(&direct_ops, ip, 1, 0);
50205073 }
50215074
5022− if (ret)
5075+ if (ret) {
50235076 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+ }
50245089 out_unlock:
50255090 mutex_unlock(&direct_mutex);
50265091
@@ -5036,6 +5101,7 @@ EXPORT_SYMBOL_GPL(register_ftrace_direct); · 9 unmodified lines
50365101 int unregister_ftrace_direct(unsigned long ip, unsigned long addr)
50375102 {
50385103 struct ftrace_func_entry *entry;
5104+ struct ftrace_direct_func *direct;
50395105 struct dyn_ftrace *rec;
50405106 int ret = -ENODEV;
50415107
@@ -5066,6 +5132,17 @@ int unregister_ftrace_direct(unsigned long ip, unsigned long addr) · 24 unmodified lines
50665132
50675133 remove_hash_entry(direct_functions, entry);
50685134
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+ }
50695146 out_unlock:
50705147 mutex_unlock(&direct_mutex);
50715148

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