diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/trace/Kconfig | 1 | ||||
-rw-r--r-- | kernel/trace/ftrace.c | 58 | ||||
-rw-r--r-- | kernel/trace/trace_functions_return.c | 15 |
3 files changed, 55 insertions, 19 deletions
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig index 9c89526b6b7c..b8378fad29a3 100644 --- a/kernel/trace/Kconfig +++ b/kernel/trace/Kconfig | |||
@@ -59,7 +59,6 @@ config FUNCTION_TRACER | |||
59 | 59 | ||
60 | config FUNCTION_RET_TRACER | 60 | config FUNCTION_RET_TRACER |
61 | bool "Kernel Function return Tracer" | 61 | bool "Kernel Function return Tracer" |
62 | depends on !DYNAMIC_FTRACE | ||
63 | depends on HAVE_FUNCTION_RET_TRACER | 62 | depends on HAVE_FUNCTION_RET_TRACER |
64 | depends on FUNCTION_TRACER | 63 | depends on FUNCTION_TRACER |
65 | help | 64 | help |
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index b42ec1de546b..2f78a45aac14 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
@@ -50,6 +50,9 @@ static int last_ftrace_enabled; | |||
50 | /* Quick disabling of function tracer. */ | 50 | /* Quick disabling of function tracer. */ |
51 | int function_trace_stop; | 51 | int function_trace_stop; |
52 | 52 | ||
53 | /* By default, current tracing type is normal tracing. */ | ||
54 | enum ftrace_tracing_type_t ftrace_tracing_type = FTRACE_TYPE_ENTER; | ||
55 | |||
53 | /* | 56 | /* |
54 | * ftrace_disabled is set when an anomaly is discovered. | 57 | * ftrace_disabled is set when an anomaly is discovered. |
55 | * ftrace_disabled is much stronger than ftrace_enabled. | 58 | * ftrace_disabled is much stronger than ftrace_enabled. |
@@ -385,12 +388,21 @@ static void ftrace_bug(int failed, unsigned long ip) | |||
385 | } | 388 | } |
386 | } | 389 | } |
387 | 390 | ||
388 | #define FTRACE_ADDR ((long)(ftrace_caller)) | ||
389 | 391 | ||
390 | static int | 392 | static int |
391 | __ftrace_replace_code(struct dyn_ftrace *rec, int enable) | 393 | __ftrace_replace_code(struct dyn_ftrace *rec, int enable) |
392 | { | 394 | { |
393 | unsigned long ip, fl; | 395 | unsigned long ip, fl; |
396 | unsigned long ftrace_addr; | ||
397 | |||
398 | #ifdef CONFIG_FUNCTION_RET_TRACER | ||
399 | if (ftrace_tracing_type == FTRACE_TYPE_ENTER) | ||
400 | ftrace_addr = (unsigned long)ftrace_caller; | ||
401 | else | ||
402 | ftrace_addr = (unsigned long)ftrace_return_caller; | ||
403 | #else | ||
404 | ftrace_addr = (unsigned long)ftrace_caller; | ||
405 | #endif | ||
394 | 406 | ||
395 | ip = rec->ip; | 407 | ip = rec->ip; |
396 | 408 | ||
@@ -450,9 +462,9 @@ __ftrace_replace_code(struct dyn_ftrace *rec, int enable) | |||
450 | } | 462 | } |
451 | 463 | ||
452 | if (rec->flags & FTRACE_FL_ENABLED) | 464 | if (rec->flags & FTRACE_FL_ENABLED) |
453 | return ftrace_make_call(rec, FTRACE_ADDR); | 465 | return ftrace_make_call(rec, ftrace_addr); |
454 | else | 466 | else |
455 | return ftrace_make_nop(NULL, rec, FTRACE_ADDR); | 467 | return ftrace_make_nop(NULL, rec, ftrace_addr); |
456 | } | 468 | } |
457 | 469 | ||
458 | static void ftrace_replace_code(int enable) | 470 | static void ftrace_replace_code(int enable) |
@@ -1405,10 +1417,17 @@ int register_ftrace_function(struct ftrace_ops *ops) | |||
1405 | return -1; | 1417 | return -1; |
1406 | 1418 | ||
1407 | mutex_lock(&ftrace_sysctl_lock); | 1419 | mutex_lock(&ftrace_sysctl_lock); |
1420 | |||
1421 | if (ftrace_tracing_type == FTRACE_TYPE_RETURN) { | ||
1422 | ret = -EBUSY; | ||
1423 | goto out; | ||
1424 | } | ||
1425 | |||
1408 | ret = __register_ftrace_function(ops); | 1426 | ret = __register_ftrace_function(ops); |
1409 | ftrace_startup(); | 1427 | ftrace_startup(); |
1410 | mutex_unlock(&ftrace_sysctl_lock); | ||
1411 | 1428 | ||
1429 | out: | ||
1430 | mutex_unlock(&ftrace_sysctl_lock); | ||
1412 | return ret; | 1431 | return ret; |
1413 | } | 1432 | } |
1414 | 1433 | ||
@@ -1474,16 +1493,45 @@ ftrace_enable_sysctl(struct ctl_table *table, int write, | |||
1474 | } | 1493 | } |
1475 | 1494 | ||
1476 | #ifdef CONFIG_FUNCTION_RET_TRACER | 1495 | #ifdef CONFIG_FUNCTION_RET_TRACER |
1496 | |||
1497 | /* The callback that hooks the return of a function */ | ||
1477 | trace_function_return_t ftrace_function_return = | 1498 | trace_function_return_t ftrace_function_return = |
1478 | (trace_function_return_t)ftrace_stub; | 1499 | (trace_function_return_t)ftrace_stub; |
1479 | void register_ftrace_return(trace_function_return_t func) | 1500 | |
1501 | int register_ftrace_return(trace_function_return_t func) | ||
1480 | { | 1502 | { |
1503 | int ret = 0; | ||
1504 | |||
1505 | mutex_lock(&ftrace_sysctl_lock); | ||
1506 | |||
1507 | /* | ||
1508 | * Don't launch return tracing if normal function | ||
1509 | * tracing is already running. | ||
1510 | */ | ||
1511 | if (ftrace_trace_function != ftrace_stub) { | ||
1512 | ret = -EBUSY; | ||
1513 | goto out; | ||
1514 | } | ||
1515 | |||
1516 | ftrace_tracing_type = FTRACE_TYPE_RETURN; | ||
1481 | ftrace_function_return = func; | 1517 | ftrace_function_return = func; |
1518 | ftrace_startup(); | ||
1519 | |||
1520 | out: | ||
1521 | mutex_unlock(&ftrace_sysctl_lock); | ||
1522 | return ret; | ||
1482 | } | 1523 | } |
1483 | 1524 | ||
1484 | void unregister_ftrace_return(void) | 1525 | void unregister_ftrace_return(void) |
1485 | { | 1526 | { |
1527 | mutex_lock(&ftrace_sysctl_lock); | ||
1528 | |||
1486 | ftrace_function_return = (trace_function_return_t)ftrace_stub; | 1529 | ftrace_function_return = (trace_function_return_t)ftrace_stub; |
1530 | ftrace_shutdown(); | ||
1531 | /* Restore normal tracing type */ | ||
1532 | ftrace_tracing_type = FTRACE_TYPE_ENTER; | ||
1533 | |||
1534 | mutex_unlock(&ftrace_sysctl_lock); | ||
1487 | } | 1535 | } |
1488 | #endif | 1536 | #endif |
1489 | 1537 | ||
diff --git a/kernel/trace/trace_functions_return.c b/kernel/trace/trace_functions_return.c index 61185f756a13..a68564af022b 100644 --- a/kernel/trace/trace_functions_return.c +++ b/kernel/trace/trace_functions_return.c | |||
@@ -14,29 +14,18 @@ | |||
14 | #include "trace.h" | 14 | #include "trace.h" |
15 | 15 | ||
16 | 16 | ||
17 | static void start_return_trace(struct trace_array *tr) | ||
18 | { | ||
19 | register_ftrace_return(&trace_function_return); | ||
20 | } | ||
21 | |||
22 | static void stop_return_trace(struct trace_array *tr) | ||
23 | { | ||
24 | unregister_ftrace_return(); | ||
25 | } | ||
26 | |||
27 | static int return_trace_init(struct trace_array *tr) | 17 | static int return_trace_init(struct trace_array *tr) |
28 | { | 18 | { |
29 | int cpu; | 19 | int cpu; |
30 | for_each_online_cpu(cpu) | 20 | for_each_online_cpu(cpu) |
31 | tracing_reset(tr, cpu); | 21 | tracing_reset(tr, cpu); |
32 | 22 | ||
33 | start_return_trace(tr); | 23 | return register_ftrace_return(&trace_function_return); |
34 | return 0; | ||
35 | } | 24 | } |
36 | 25 | ||
37 | static void return_trace_reset(struct trace_array *tr) | 26 | static void return_trace_reset(struct trace_array *tr) |
38 | { | 27 | { |
39 | stop_return_trace(tr); | 28 | unregister_ftrace_return(); |
40 | } | 29 | } |
41 | 30 | ||
42 | 31 | ||