diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/trace/trace_uprobe.c | 93 |
1 files changed, 56 insertions, 37 deletions
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c index c5d2612bf233..d83155e0da78 100644 --- a/kernel/trace/trace_uprobe.c +++ b/kernel/trace/trace_uprobe.c | |||
| @@ -759,30 +759,25 @@ static void uprobe_buffer_put(struct uprobe_cpu_buffer *ucb) | |||
| 759 | } | 759 | } |
| 760 | 760 | ||
| 761 | static void __uprobe_trace_func(struct trace_uprobe *tu, | 761 | static void __uprobe_trace_func(struct trace_uprobe *tu, |
| 762 | unsigned long func, struct pt_regs *regs) | 762 | unsigned long func, struct pt_regs *regs, |
| 763 | struct uprobe_cpu_buffer *ucb, int dsize) | ||
| 763 | { | 764 | { |
| 764 | struct uprobe_trace_entry_head *entry; | 765 | struct uprobe_trace_entry_head *entry; |
| 765 | struct ring_buffer_event *event; | 766 | struct ring_buffer_event *event; |
| 766 | struct ring_buffer *buffer; | 767 | struct ring_buffer *buffer; |
| 767 | struct uprobe_cpu_buffer *ucb; | ||
| 768 | void *data; | 768 | void *data; |
| 769 | int size, dsize, esize; | 769 | int size, esize; |
| 770 | struct ftrace_event_call *call = &tu->tp.call; | 770 | struct ftrace_event_call *call = &tu->tp.call; |
| 771 | 771 | ||
| 772 | dsize = __get_data_size(&tu->tp, regs); | 772 | if (WARN_ON_ONCE(tu->tp.size + dsize > PAGE_SIZE)) |
| 773 | esize = SIZEOF_TRACE_ENTRY(is_ret_probe(tu)); | ||
| 774 | |||
| 775 | if (WARN_ON_ONCE(!uprobe_cpu_buffer || tu->tp.size + dsize > PAGE_SIZE)) | ||
| 776 | return; | 773 | return; |
| 777 | 774 | ||
| 778 | ucb = uprobe_buffer_get(); | 775 | esize = SIZEOF_TRACE_ENTRY(is_ret_probe(tu)); |
| 779 | store_trace_args(esize, &tu->tp, regs, ucb->buf, dsize); | ||
| 780 | |||
| 781 | size = esize + tu->tp.size + dsize; | 776 | size = esize + tu->tp.size + dsize; |
| 782 | event = trace_current_buffer_lock_reserve(&buffer, call->event.type, | 777 | event = trace_current_buffer_lock_reserve(&buffer, call->event.type, |
| 783 | size, 0, 0); | 778 | size, 0, 0); |
| 784 | if (!event) | 779 | if (!event) |
| 785 | goto out; | 780 | return; |
| 786 | 781 | ||
| 787 | entry = ring_buffer_event_data(event); | 782 | entry = ring_buffer_event_data(event); |
| 788 | if (is_ret_probe(tu)) { | 783 | if (is_ret_probe(tu)) { |
| @@ -798,23 +793,22 @@ static void __uprobe_trace_func(struct trace_uprobe *tu, | |||
| 798 | 793 | ||
| 799 | if (!call_filter_check_discard(call, entry, buffer, event)) | 794 | if (!call_filter_check_discard(call, entry, buffer, event)) |
| 800 | trace_buffer_unlock_commit(buffer, event, 0, 0); | 795 | trace_buffer_unlock_commit(buffer, event, 0, 0); |
| 801 | |||
| 802 | out: | ||
| 803 | uprobe_buffer_put(ucb); | ||
| 804 | } | 796 | } |
| 805 | 797 | ||
| 806 | /* uprobe handler */ | 798 | /* uprobe handler */ |
| 807 | static int uprobe_trace_func(struct trace_uprobe *tu, struct pt_regs *regs) | 799 | static int uprobe_trace_func(struct trace_uprobe *tu, struct pt_regs *regs, |
| 800 | struct uprobe_cpu_buffer *ucb, int dsize) | ||
| 808 | { | 801 | { |
| 809 | if (!is_ret_probe(tu)) | 802 | if (!is_ret_probe(tu)) |
| 810 | __uprobe_trace_func(tu, 0, regs); | 803 | __uprobe_trace_func(tu, 0, regs, ucb, dsize); |
| 811 | return 0; | 804 | return 0; |
| 812 | } | 805 | } |
| 813 | 806 | ||
| 814 | static void uretprobe_trace_func(struct trace_uprobe *tu, unsigned long func, | 807 | static void uretprobe_trace_func(struct trace_uprobe *tu, unsigned long func, |
| 815 | struct pt_regs *regs) | 808 | struct pt_regs *regs, |
| 809 | struct uprobe_cpu_buffer *ucb, int dsize) | ||
| 816 | { | 810 | { |
| 817 | __uprobe_trace_func(tu, func, regs); | 811 | __uprobe_trace_func(tu, func, regs, ucb, dsize); |
| 818 | } | 812 | } |
| 819 | 813 | ||
| 820 | /* Event entry printers */ | 814 | /* Event entry printers */ |
| @@ -1015,30 +1009,23 @@ static bool uprobe_perf_filter(struct uprobe_consumer *uc, | |||
| 1015 | } | 1009 | } |
| 1016 | 1010 | ||
| 1017 | static void __uprobe_perf_func(struct trace_uprobe *tu, | 1011 | static void __uprobe_perf_func(struct trace_uprobe *tu, |
| 1018 | unsigned long func, struct pt_regs *regs) | 1012 | unsigned long func, struct pt_regs *regs, |
| 1013 | struct uprobe_cpu_buffer *ucb, int dsize) | ||
| 1019 | { | 1014 | { |
| 1020 | struct ftrace_event_call *call = &tu->tp.call; | 1015 | struct ftrace_event_call *call = &tu->tp.call; |
| 1021 | struct uprobe_trace_entry_head *entry; | 1016 | struct uprobe_trace_entry_head *entry; |
| 1022 | struct hlist_head *head; | 1017 | struct hlist_head *head; |
| 1023 | struct uprobe_cpu_buffer *ucb; | ||
| 1024 | void *data; | 1018 | void *data; |
| 1025 | int size, dsize, esize; | 1019 | int size, esize; |
| 1026 | int rctx; | 1020 | int rctx; |
| 1027 | 1021 | ||
| 1028 | dsize = __get_data_size(&tu->tp, regs); | ||
| 1029 | esize = SIZEOF_TRACE_ENTRY(is_ret_probe(tu)); | 1022 | esize = SIZEOF_TRACE_ENTRY(is_ret_probe(tu)); |
| 1030 | 1023 | ||
| 1031 | if (WARN_ON_ONCE(!uprobe_cpu_buffer)) | ||
| 1032 | return; | ||
| 1033 | |||
| 1034 | size = esize + tu->tp.size + dsize; | 1024 | size = esize + tu->tp.size + dsize; |
| 1035 | size = ALIGN(size + sizeof(u32), sizeof(u64)) - sizeof(u32); | 1025 | size = ALIGN(size + sizeof(u32), sizeof(u64)) - sizeof(u32); |
| 1036 | if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE, "profile buffer not large enough")) | 1026 | if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE, "profile buffer not large enough")) |
| 1037 | return; | 1027 | return; |
| 1038 | 1028 | ||
| 1039 | ucb = uprobe_buffer_get(); | ||
| 1040 | store_trace_args(esize, &tu->tp, regs, ucb->buf, dsize); | ||
| 1041 | |||
| 1042 | preempt_disable(); | 1029 | preempt_disable(); |
| 1043 | head = this_cpu_ptr(call->perf_events); | 1030 | head = this_cpu_ptr(call->perf_events); |
| 1044 | if (hlist_empty(head)) | 1031 | if (hlist_empty(head)) |
| @@ -1068,24 +1055,25 @@ static void __uprobe_perf_func(struct trace_uprobe *tu, | |||
| 1068 | perf_trace_buf_submit(entry, size, rctx, 0, 1, regs, head, NULL); | 1055 | perf_trace_buf_submit(entry, size, rctx, 0, 1, regs, head, NULL); |
| 1069 | out: | 1056 | out: |
| 1070 | preempt_enable(); | 1057 | preempt_enable(); |
| 1071 | uprobe_buffer_put(ucb); | ||
| 1072 | } | 1058 | } |
| 1073 | 1059 | ||
| 1074 | /* uprobe profile handler */ | 1060 | /* uprobe profile handler */ |
| 1075 | static int uprobe_perf_func(struct trace_uprobe *tu, struct pt_regs *regs) | 1061 | static int uprobe_perf_func(struct trace_uprobe *tu, struct pt_regs *regs, |
| 1062 | struct uprobe_cpu_buffer *ucb, int dsize) | ||
| 1076 | { | 1063 | { |
| 1077 | if (!uprobe_perf_filter(&tu->consumer, 0, current->mm)) | 1064 | if (!uprobe_perf_filter(&tu->consumer, 0, current->mm)) |
| 1078 | return UPROBE_HANDLER_REMOVE; | 1065 | return UPROBE_HANDLER_REMOVE; |
| 1079 | 1066 | ||
| 1080 | if (!is_ret_probe(tu)) | 1067 | if (!is_ret_probe(tu)) |
| 1081 | __uprobe_perf_func(tu, 0, regs); | 1068 | __uprobe_perf_func(tu, 0, regs, ucb, dsize); |
| 1082 | return 0; | 1069 | return 0; |
| 1083 | } | 1070 | } |
| 1084 | 1071 | ||
| 1085 | static void uretprobe_perf_func(struct trace_uprobe *tu, unsigned long func, | 1072 | static void uretprobe_perf_func(struct trace_uprobe *tu, unsigned long func, |
| 1086 | struct pt_regs *regs) | 1073 | struct pt_regs *regs, |
| 1074 | struct uprobe_cpu_buffer *ucb, int dsize) | ||
| 1087 | { | 1075 | { |
| 1088 | __uprobe_perf_func(tu, func, regs); | 1076 | __uprobe_perf_func(tu, func, regs, ucb, dsize); |
| 1089 | } | 1077 | } |
| 1090 | #endif /* CONFIG_PERF_EVENTS */ | 1078 | #endif /* CONFIG_PERF_EVENTS */ |
| 1091 | 1079 | ||
| @@ -1127,8 +1115,11 @@ static int uprobe_dispatcher(struct uprobe_consumer *con, struct pt_regs *regs) | |||
| 1127 | { | 1115 | { |
| 1128 | struct trace_uprobe *tu; | 1116 | struct trace_uprobe *tu; |
| 1129 | struct uprobe_dispatch_data udd; | 1117 | struct uprobe_dispatch_data udd; |
| 1118 | struct uprobe_cpu_buffer *ucb; | ||
| 1119 | int dsize, esize; | ||
| 1130 | int ret = 0; | 1120 | int ret = 0; |
| 1131 | 1121 | ||
| 1122 | |||
| 1132 | tu = container_of(con, struct trace_uprobe, consumer); | 1123 | tu = container_of(con, struct trace_uprobe, consumer); |
| 1133 | tu->nhit++; | 1124 | tu->nhit++; |
| 1134 | 1125 | ||
| @@ -1137,13 +1128,29 @@ static int uprobe_dispatcher(struct uprobe_consumer *con, struct pt_regs *regs) | |||
| 1137 | 1128 | ||
| 1138 | current->utask->vaddr = (unsigned long) &udd; | 1129 | current->utask->vaddr = (unsigned long) &udd; |
| 1139 | 1130 | ||
| 1131 | #ifdef CONFIG_PERF_EVENTS | ||
| 1132 | if ((tu->tp.flags & TP_FLAG_TRACE) == 0 && | ||
| 1133 | !uprobe_perf_filter(&tu->consumer, 0, current->mm)) | ||
| 1134 | return UPROBE_HANDLER_REMOVE; | ||
| 1135 | #endif | ||
| 1136 | |||
| 1137 | if (WARN_ON_ONCE(!uprobe_cpu_buffer)) | ||
| 1138 | return 0; | ||
| 1139 | |||
| 1140 | dsize = __get_data_size(&tu->tp, regs); | ||
| 1141 | esize = SIZEOF_TRACE_ENTRY(is_ret_probe(tu)); | ||
| 1142 | |||
