Fix: instruction pointer has different names across arch
[lttng-modules.git] / probes / lttng-uprobes.c
CommitLineData
149b9a9d
YB
1/*
2 * probes/lttng-uprobes.c
3 *
4 * LTTng uprobes integration module.
5 *
6 * Copyright (C) 2013 Yannick Brosseau <yannick.brosseau@gmail.com>
7 * Copyright (C) 2009-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; only
12 * version 2.1 of the License.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24#include <linux/fdtable.h>
3aed4dca 25#include <linux/list.h>
149b9a9d
YB
26#include <linux/module.h>
27#include <linux/namei.h>
28#include <linux/slab.h>
3aed4dca 29#include <linux/uaccess.h>
149b9a9d
YB
30#include <lttng-events.h>
31#include <lttng-tracer.h>
32#include <wrapper/irqflags.h>
33#include <wrapper/ringbuffer/frontend_types.h>
34#include <wrapper/uprobes.h>
35#include <wrapper/vmalloc.h>
36
37static
38int lttng_uprobes_handler_pre(struct uprobe_consumer *uc, struct pt_regs *regs)
39{
3aed4dca
FD
40 struct lttng_uprobe_handler *uprobe_handler =
41 container_of(uc, struct lttng_uprobe_handler, up_consumer);
42 struct lttng_event *event = uprobe_handler->event;
149b9a9d
YB
43 struct lttng_probe_ctx lttng_probe_ctx = {
44 .event = event,
45 .interruptible = !lttng_regs_irqs_disabled(regs),
46 };
47 struct lttng_channel *chan = event->chan;
48 struct lib_ring_buffer_ctx ctx;
49 int ret;
50
51 struct {
52 unsigned long ip;
56377c91 53 } payload;
149b9a9d
YB
54
55 if (unlikely(!ACCESS_ONCE(chan->session->active)))
56 return 0;
57 if (unlikely(!ACCESS_ONCE(chan->enabled)))
58 return 0;
59 if (unlikely(!ACCESS_ONCE(event->enabled)))
60 return 0;
61
62 lib_ring_buffer_ctx_init(&ctx, chan->chan, &lttng_probe_ctx,
63 sizeof(payload), lttng_alignof(payload), -1);
64
65 ret = chan->ops->event_reserve(&ctx, event->id);
66 if (ret < 0)
67 return 0;
68
69 /* Event payload. */
7445d54f 70 payload.ip = (unsigned long)instruction_pointer(regs);
56377c91 71
149b9a9d
YB
72 lib_ring_buffer_align_ctx(&ctx, lttng_alignof(payload));
73 chan->ops->event_write(&ctx, &payload, sizeof(payload));
74 chan->ops->event_commit(&ctx);
75 return 0;
76}
77
78/*
79 * Create event description.
80 */
81static
82int lttng_create_uprobe_event(const char *name, struct lttng_event *event)
83{
84 struct lttng_event_desc *desc;
85 struct lttng_event_field *fields;
86 int ret;
87
88 desc = kzalloc(sizeof(*event->desc), GFP_KERNEL);
89 if (!desc)
90 return -ENOMEM;
91 desc->name = kstrdup(name, GFP_KERNEL);
92 if (!desc->name) {
93 ret = -ENOMEM;
94 goto error_str;
95 }
96
97 desc->nr_fields = 1;
98 desc->fields = fields =
99 kzalloc(1 * sizeof(struct lttng_event_field), GFP_KERNEL);
100
101 if (!desc->fields) {
102 ret = -ENOMEM;
103 goto error_fields;
104 }
105 fields[0].name = "ip";
106 fields[0].type.atype = atype_integer;
107 fields[0].type.u.basic.integer.size = sizeof(unsigned long) * CHAR_BIT;
108 fields[0].type.u.basic.integer.alignment = lttng_alignof(unsigned long) * CHAR_BIT;
109 fields[0].type.u.basic.integer.signedness = lttng_is_signed_type(unsigned long);
110 fields[0].type.u.basic.integer.reverse_byte_order = 0;
111 fields[0].type.u.basic.integer.base = 16;
112 fields[0].type.u.basic.integer.encoding = lttng_encode_none;
113
114 desc->owner = THIS_MODULE;
115 event->desc = desc;
116
117 return 0;
118
119error_fields:
120 kfree(desc->name);
121error_str:
122 kfree(desc);
123 return ret;
124}
125
56377c91
FD
126/*
127 * Returns the inode struct from the current task and an fd. The inode is
128 * grabbed by this function and must be put once we are done with it using
129 * iput().
130 */
131static struct inode *get_inode_from_fd(int fd)
132{
133 struct file *file;
134 struct inode *inode;
135
136 rcu_read_lock();
137 /*
138 * Returns the file backing the given fd. Needs to be done inside an RCU
139 * critical section.
140 */
141 file = fcheck(fd);
142 if (file == NULL) {
143 printk(KERN_WARNING "Cannot access file backing the fd(%d)\n", fd);
144 inode = NULL;
145 goto error;
146 }
147
148 /* Grab a reference on the inode. */
149 inode = igrab(file->f_path.dentry->d_inode);
150 if (inode == NULL)
151 printk(KERN_WARNING "Cannot grab a reference on the inode.\n");
152error:
153 rcu_read_unlock();
154 return inode;
155}
156
3aed4dca
FD
157int lttng_uprobes_add_callsite(struct lttng_event *event,
158 struct lttng_kernel_event_callsite __user *callsite)
149b9a9d 159{
3aed4dca
FD
160 int ret = 0;
161 struct lttng_uprobe_handler *uprobe_handler;
162
163 if (!event) {
164 ret = -EINVAL;
165 goto end;
166 }
167
168 uprobe_handler = kzalloc(sizeof(struct lttng_uprobe_handler), GFP_KERNEL);
169 if (!uprobe_handler) {
170 printk(KERN_WARNING "Error allocating uprobe_uprobe_handlers");
171 ret = -ENOMEM;
172 goto end;
173 }
174
175 /* Ensure the memory we just allocated don't trigger page faults. */
176 wrapper_vmalloc_sync_all();
177
178 uprobe_handler->event = event;
179 uprobe_handler->up_consumer.handler = lttng_uprobes_handler_pre;
180
181 ret = copy_from_user(&uprobe_handler->offset, &callsite->u.uprobe.offset, sizeof(uint64_t));
182 if (ret) {
183 goto register_error;
184 }
185
186 ret = wrapper_uprobe_register(event->u.uprobe.inode,
187 uprobe_handler->offset, &uprobe_handler->up_consumer);
188 if (ret) {
189 printk(KERN_WARNING "Error registering probe on inode %lu "
190 "and offset 0x%llx\n", event->u.uprobe.inode->i_ino,
191 uprobe_handler->offset);
192 ret = -1;
193 goto register_error;
194 }
195
196 list_add(&uprobe_handler->node, &event->u.uprobe.head);
197
198 return ret;
199
200register_error:
201 kfree(uprobe_handler);
202end:
203 return ret;
204}
205EXPORT_SYMBOL_GPL(lttng_uprobes_add_callsite);
206
207int lttng_uprobes_register(const char *name, int fd, struct lttng_event *event)
208{
209 int ret = 0;
56377c91 210 struct inode *inode;
149b9a9d
YB
211
212 ret = lttng_create_uprobe_event(name, event);
213 if (ret)
214 goto error;
215
56377c91
FD
216 inode = get_inode_from_fd(fd);
217 if (!inode) {
218 printk(KERN_WARNING "Cannot get inode from fd\n");
219 ret = -EBADF;
220 goto inode_error;
221 }
56377c91 222 event->u.uprobe.inode = inode;
3aed4dca 223 INIT_LIST_HEAD(&event->u.uprobe.head);
149b9a9d 224
149b9a9d
YB
225 return 0;
226
56377c91 227inode_error:
149b9a9d
YB
228 kfree(event->desc->name);
229 kfree(event->desc);
230error:
231 return ret;
232}
233EXPORT_SYMBOL_GPL(lttng_uprobes_register);
234
235void lttng_uprobes_unregister(struct lttng_event *event)
236{
3aed4dca
FD
237 struct lttng_uprobe_handler *iter, *tmp;
238
239 /*
240 * Iterate over the list of handler, remove each handler from the list
241 * and free the struct.
242 */
243 list_for_each_entry_safe(iter, tmp, &event->u.uprobe.head, node) {
244 wrapper_uprobe_unregister(event->u.uprobe.inode, iter->offset,
245 &iter->up_consumer);
246 list_del(&iter->node);
247 kfree(iter);
248 }
149b9a9d
YB
249}
250EXPORT_SYMBOL_GPL(lttng_uprobes_unregister);
251
252void lttng_uprobes_destroy_private(struct lttng_event *event)
253{
254 iput(event->u.uprobe.inode);
255 kfree(event->desc->name);
256 kfree(event->desc);
257}
258EXPORT_SYMBOL_GPL(lttng_uprobes_destroy_private);
259
260MODULE_LICENSE("GPL and additional rights");
261MODULE_AUTHOR("Yannick Brosseau");
262MODULE_DESCRIPTION("Linux Trace Toolkit Uprobes Support");
This page took 0.032858 seconds and 4 git commands to generate.