blob: 2010520a9d3ab02e28473a3f27188228cba4f630 [file] [log] [blame]
Vicent Marti0865f942016-04-27 16:57:58 +02001/*
2 * Copyright (c) 2016 GitHub, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Teng Qin488c1192017-09-13 10:47:59 -070016#include <algorithm>
Vicent Martieca47832016-05-01 12:53:46 +020017#include <cstring>
Vicent Marti1a2ddac2016-05-01 13:41:33 +020018#include <sstream>
Yonghong Song0ba15072017-07-21 22:13:20 -070019#include <unordered_set>
Vicent Marti0865f942016-04-27 16:57:58 +020020
Vicent Marti92598412016-04-28 19:42:55 +020021#include <fcntl.h>
Javier Honduvilla Cotodcb9b9a2018-05-14 13:02:05 +020022#include <sys/stat.h>
Vicent Marti92598412016-04-28 19:42:55 +020023#include <sys/types.h>
24#include <unistd.h>
25
Vicent Marti0865f942016-04-27 16:57:58 +020026#include "bcc_elf.h"
Vicent Marti92598412016-04-28 19:42:55 +020027#include "bcc_proc.h"
Teng Qin97562952017-09-18 13:36:49 -070028#include "common.h"
Vicent Marti0865f942016-04-27 16:57:58 +020029#include "usdt.h"
30#include "vendor/tinyformat.hpp"
Sasha Goldshtein69e361a2016-09-27 19:40:00 +030031#include "bcc_usdt.h"
Vicent Marti0865f942016-04-27 16:57:58 +020032
33namespace USDT {
34
Yonghong Song24894572018-01-04 22:08:51 -080035Location::Location(uint64_t addr, const std::string &bin_path, const char *arg_fmt)
36 : address_(addr),
37 bin_path_(bin_path) {
38
Yonghong Songc2d98802017-10-26 10:55:05 -070039#ifdef __aarch64__
40 ArgumentParser_aarch64 parser(arg_fmt);
41#elif __powerpc64__
Sandipan Das1f0f7b62017-09-26 15:29:18 +053042 ArgumentParser_powerpc64 parser(arg_fmt);
Sandipan Das1f0f7b62017-09-26 15:29:18 +053043#else
Sandipan Das9ab1cee2017-10-10 10:29:29 +053044 ArgumentParser_x64 parser(arg_fmt);
Sandipan Das1f0f7b62017-09-26 15:29:18 +053045#endif
Vicent Marti0865f942016-04-27 16:57:58 +020046 while (!parser.done()) {
Vicent Martieca47832016-05-01 12:53:46 +020047 Argument arg;
48 if (!parser.parse(&arg))
Vicent Marti0865f942016-04-27 16:57:58 +020049 continue;
Vicent Martieca47832016-05-01 12:53:46 +020050 arguments_.push_back(std::move(arg));
Vicent Marti0865f942016-04-27 16:57:58 +020051 }
52}
53
54Probe::Probe(const char *bin_path, const char *provider, const char *name,
Vicent Marti96c1b8e2017-06-27 19:06:46 +020055 uint64_t semaphore, const optional<int> &pid, ProcMountNS *ns)
Vicent Marti0865f942016-04-27 16:57:58 +020056 : bin_path_(bin_path),
57 provider_(provider),
58 name_(name),
Vicent Marti10436452016-05-04 16:58:51 +020059 semaphore_(semaphore),
Vicent Marti96c1b8e2017-06-27 19:06:46 +020060 pid_(pid),
61 mount_ns_(ns) {}
Vicent Marti0865f942016-04-27 16:57:58 +020062
Yonghong Song24894572018-01-04 22:08:51 -080063bool Probe::in_shared_object(const std::string &bin_path) {
64 if (object_type_map_.find(bin_path) == object_type_map_.end()) {
65 ProcMountNSGuard g(mount_ns_);
66 return (object_type_map_[bin_path] = bcc_elf_is_shared_obj(bin_path.c_str()));
67 }
68 return object_type_map_[bin_path];
Vicent Marti92598412016-04-28 19:42:55 +020069}
70
Yonghong Song24894572018-01-04 22:08:51 -080071bool Probe::resolve_global_address(uint64_t *global, const std::string &bin_path,
72 const uint64_t addr) {
73 if (in_shared_object(bin_path)) {
Vicent Marti040df7d2016-05-04 16:59:57 +020074 return (pid_ &&
Yonghong Song24894572018-01-04 22:08:51 -080075 !bcc_resolve_global_addr(*pid_, bin_path.c_str(), addr, global));
Vicent Martieca47832016-05-01 12:53:46 +020076 }
77
78 *global = addr;
79 return true;
80}
81
Vicent Marti10436452016-05-04 16:58:51 +020082bool Probe::add_to_semaphore(int16_t val) {
Sasha Goldshtein9ca8ac22017-03-03 15:13:16 -050083 assert(pid_);
Vicent Marti10436452016-05-04 16:58:51 +020084
85 if (!attached_semaphore_) {
86 uint64_t addr;
Yonghong Song24894572018-01-04 22:08:51 -080087 if (!resolve_global_address(&addr, bin_path_, semaphore_))
Vicent Marti10436452016-05-04 16:58:51 +020088 return false;
89 attached_semaphore_ = addr;
Vicent Marti92598412016-04-28 19:42:55 +020090 }
91
Vicent Marti10436452016-05-04 16:58:51 +020092 off_t address = static_cast<off_t>(attached_semaphore_.value());
Vicent Marti92598412016-04-28 19:42:55 +020093
Vicent Marti10436452016-05-04 16:58:51 +020094 std::string procmem = tfm::format("/proc/%d/mem", pid_.value());
Vicent Marti92598412016-04-28 19:42:55 +020095 int memfd = ::open(procmem.c_str(), O_RDWR);
96 if (memfd < 0)
97 return false;
98
Vicent Marti10436452016-05-04 16:58:51 +020099 int16_t original;
Vicent Marti92598412016-04-28 19:42:55 +0200100
Vicent Marti10436452016-05-04 16:58:51 +0200101 if (::lseek(memfd, address, SEEK_SET) < 0 ||
Vicent Marti92598412016-04-28 19:42:55 +0200102 ::read(memfd, &original, 2) != 2) {
103 ::close(memfd);
104 return false;
105 }
106
107 original = original + val;
108
Vicent Marti10436452016-05-04 16:58:51 +0200109 if (::lseek(memfd, address, SEEK_SET) < 0 ||
Vicent Marti92598412016-04-28 19:42:55 +0200110 ::write(memfd, &original, 2) != 2) {
111 ::close(memfd);
112 return false;
113 }
114
115 ::close(memfd);
116 return true;
117}
118
Vicent Marti10436452016-05-04 16:58:51 +0200119bool Probe::enable(const std::string &fn_name) {
120 if (attached_to_)
Vicent Marti92598412016-04-28 19:42:55 +0200121 return false;
122
Vicent Marti10436452016-05-04 16:58:51 +0200123 if (need_enable()) {
124 if (!pid_)
125 return false;
126
127 if (!add_to_semaphore(+1))
128 return false;
129 }
130
131 attached_to_ = fn_name;
Vicent Marti92598412016-04-28 19:42:55 +0200132 return true;
133}
134
Vicent Marti10436452016-05-04 16:58:51 +0200135bool Probe::disable() {
136 if (!attached_to_)
Vicent Marti92598412016-04-28 19:42:55 +0200137 return false;
138
Vicent Marti10436452016-05-04 16:58:51 +0200139 attached_to_ = nullopt;
Vicent Marti92598412016-04-28 19:42:55 +0200140
Vicent Marti10436452016-05-04 16:58:51 +0200141 if (need_enable()) {
142 assert(pid_);
143 return add_to_semaphore(-1);
144 }
145 return true;
Vicent Marti92598412016-04-28 19:42:55 +0200146}
147
Vicent Martieca47832016-05-01 12:53:46 +0200148std::string Probe::largest_arg_type(size_t arg_n) {
149 Argument *largest = nullptr;
150 for (Location &location : locations_) {
151 Argument *candidate = &location.arguments_[arg_n];
152 if (!largest ||
Vicent Marti1a2ddac2016-05-01 13:41:33 +0200153 std::abs(candidate->arg_size()) > std::abs(largest->arg_size()))
Vicent Martieca47832016-05-01 12:53:46 +0200154 largest = candidate;
155 }
156
157 assert(largest);
158 return largest->ctype();
159}
160
Vicent Marti10436452016-05-04 16:58:51 +0200161bool Probe::usdt_getarg(std::ostream &stream) {
Teng Qin8265aca2018-06-26 08:33:34 -0700162 if (!attached_to_ || attached_to_->empty())
Vicent Marti10436452016-05-04 16:58:51 +0200163 return false;
164
Teng Qin8265aca2018-06-26 08:33:34 -0700165 return usdt_getarg(stream, attached_to_.value());
166}
167
168bool Probe::usdt_getarg(std::ostream &stream, const std::string& probe_func) {
169 const size_t arg_count = locations_[0].arguments_.size();
170
Vicent Martieca47832016-05-01 12:53:46 +0200171 if (arg_count == 0)
172 return true;
173
174 for (size_t arg_n = 0; arg_n < arg_count; ++arg_n) {
175 std::string ctype = largest_arg_type(arg_n);
Yonghong Songe09564d2017-06-05 17:55:24 -0700176 std::string cptr = tfm::format("*((%s *)dest)", ctype);
Vicent Marti4ea4af42016-05-04 13:01:55 +0200177
Vicent Martieca47832016-05-01 12:53:46 +0200178 tfm::format(stream,
Sasha Goldshtein2070a2a2017-05-03 07:07:23 -0400179 "static __always_inline int _bpf_readarg_%s_%d("
Vicent Marti040df7d2016-05-04 16:59:57 +0200180 "struct pt_regs *ctx, void *dest, size_t len) {\n"
181 " if (len != sizeof(%s)) return -1;\n",
Teng Qin8265aca2018-06-26 08:33:34 -0700182 probe_func, arg_n + 1, ctype);
Vicent Martieca47832016-05-01 12:53:46 +0200183
184 if (locations_.size() == 1) {
185 Location &location = locations_.front();
186 stream << " ";
Yonghong Song24894572018-01-04 22:08:51 -0800187 if (!location.arguments_[arg_n].assign_to_local(stream, cptr, location.bin_path_,
Vicent Marti040df7d2016-05-04 16:59:57 +0200188 pid_))
Vicent Marti1a2ddac2016-05-01 13:41:33 +0200189 return false;
Vicent Marti4ea4af42016-05-04 13:01:55 +0200190 stream << "\n return 0;\n}\n";
Vicent Martieca47832016-05-01 12:53:46 +0200191 } else {
Sandipan Das1f0f7b62017-09-26 15:29:18 +0530192 stream << " switch(PT_REGS_IP(ctx)) {\n";
Vicent Martieca47832016-05-01 12:53:46 +0200193 for (Location &location : locations_) {
Vicent Marti1a2ddac2016-05-01 13:41:33 +0200194 uint64_t global_address;
Vicent Martieca47832016-05-01 12:53:46 +0200195
Yonghong Song24894572018-01-04 22:08:51 -0800196 if (!resolve_global_address(&global_address, location.bin_path_,
197 location.address_))
Vicent Marti1a2ddac2016-05-01 13:41:33 +0200198 return false;
Vicent Martieca47832016-05-01 12:53:46 +0200199
Vicent Marti1a2ddac2016-05-01 13:41:33 +0200200 tfm::format(stream, " case 0x%xULL: ", global_address);
Yonghong Song24894572018-01-04 22:08:51 -0800201 if (!location.arguments_[arg_n].assign_to_local(stream, cptr, location.bin_path_,
Vicent Marti040df7d2016-05-04 16:59:57 +0200202 pid_))
Vicent Marti1a2ddac2016-05-01 13:41:33 +0200203 return false;
Vicent Martieca47832016-05-01 12:53:46 +0200204
Vicent Marti4ea4af42016-05-04 13:01:55 +0200205 stream << " return 0;\n";
Vicent Martieca47832016-05-01 12:53:46 +0200206 }
207 stream << " }\n";
Vicent Marti4ea4af42016-05-04 13:01:55 +0200208 stream << " return -1;\n}\n";
Vicent Martieca47832016-05-01 12:53:46 +0200209 }
Vicent Martieca47832016-05-01 12:53:46 +0200210 }
211 return true;
212}
213
Yonghong Song24894572018-01-04 22:08:51 -0800214void Probe::add_location(uint64_t addr, const std::string &bin_path, const char *fmt) {
215 locations_.emplace_back(addr, bin_path, fmt);
Vicent Marti0865f942016-04-27 16:57:58 +0200216}
217
Teng Qin488c1192017-09-13 10:47:59 -0700218void Probe::finalize_locations() {
219 std::sort(locations_.begin(), locations_.end(),
220 [](const Location &a, const Location &b) {
Yonghong Song24894572018-01-04 22:08:51 -0800221 return a.bin_path_ < b.bin_path_ || a.address_ < b.address_;
Teng Qin488c1192017-09-13 10:47:59 -0700222 });
223 auto last = std::unique(locations_.begin(), locations_.end(),
224 [](const Location &a, const Location &b) {
Yonghong Song24894572018-01-04 22:08:51 -0800225 return a.bin_path_ == b.bin_path_ && a.address_ == b.address_;
Teng Qin488c1192017-09-13 10:47:59 -0700226 });
227 locations_.erase(last, locations_.end());
228}
229
Vicent Marti0865f942016-04-27 16:57:58 +0200230void Context::_each_probe(const char *binpath, const struct bcc_elf_usdt *probe,
231 void *p) {
232 Context *ctx = static_cast<Context *>(p);
233 ctx->add_probe(binpath, probe);
234}
235
Teng Qina0c5de12017-09-25 15:13:23 -0700236int Context::_each_module(const char *modpath, uint64_t, uint64_t, uint64_t,
237 bool, void *p) {
Sasha Goldshtein69948a62017-03-03 08:00:55 -0500238 Context *ctx = static_cast<Context *>(p);
239 // Modules may be reported multiple times if they contain more than one
240 // executable region. We are going to parse the ELF on disk anyway, so we
241 // don't need these duplicates.
242 if (ctx->modules_.insert(modpath).second /*inserted new?*/) {
Vicent Marti96c1b8e2017-06-27 19:06:46 +0200243 ProcMountNSGuard g(ctx->mount_ns_instance_.get());
Sasha Goldshtein69948a62017-03-03 08:00:55 -0500244 bcc_elf_foreach_usdt(modpath, _each_probe, p);
245 }
Vicent Marti92598412016-04-28 19:42:55 +0200246 return 0;
247}
248
Vicent Marti0865f942016-04-27 16:57:58 +0200249void Context::add_probe(const char *binpath, const struct bcc_elf_usdt *probe) {
Vicent Marti10436452016-05-04 16:58:51 +0200250 for (auto &p : probes_) {
Vicent Marti0865f942016-04-27 16:57:58 +0200251 if (p->provider_ == probe->provider && p->name_ == probe->name) {
Yonghong Song24894572018-01-04 22:08:51 -0800252 p->add_location(probe->pc, binpath, probe->arg_fmt);
Vicent Marti10436452016-05-04 16:58:51 +0200253 return;
Vicent Marti0865f942016-04-27 16:57:58 +0200254 }
255 }
256
Vicent Marti040df7d2016-05-04 16:59:57 +0200257 probes_.emplace_back(
Vicent Marti96c1b8e2017-06-27 19:06:46 +0200258 new Probe(binpath, probe->provider, probe->name, probe->semaphore, pid_,
259 mount_ns_instance_.get()));
Yonghong Song24894572018-01-04 22:08:51 -0800260 probes_.back()->add_location(probe->pc, binpath, probe->arg_fmt);
Vicent Marti0865f942016-04-27 16:57:58 +0200261}
262
Vicent Marti92598412016-04-28 19:42:55 +0200263std::string Context::resolve_bin_path(const std::string &bin_path) {
264 std::string result;
265
266 if (char *which = bcc_procutils_which(bin_path.c_str())) {
267 result = which;
268 ::free(which);
Paul Chaignon81654bf2017-01-15 10:11:42 +0100269 } else if (char *which_so = bcc_procutils_which_so(bin_path.c_str(), 0)) {
Vicent Marti92598412016-04-28 19:42:55 +0200270 result = which_so;
Paul Chaignon81654bf2017-01-15 10:11:42 +0100271 ::free(which_so);
Vicent Marti92598412016-04-28 19:42:55 +0200272 }
273
274 return result;
Vicent Marti0865f942016-04-27 16:57:58 +0200275}
276
Vicent Marti11606082016-05-06 10:51:54 +0200277Probe *Context::get(const std::string &probe_name) {
Vicent Marti10436452016-05-04 16:58:51 +0200278 for (auto &p : probes_) {
Vicent Marti92598412016-04-28 19:42:55 +0200279 if (p->name_ == probe_name)
Vicent Marti11606082016-05-06 10:51:54 +0200280 return p.get();
Vicent Marti92598412016-04-28 19:42:55 +0200281 }
282 return nullptr;
283}
Vicent Marti0865f942016-04-27 16:57:58 +0200284
Yonghong Song24894572018-01-04 22:08:51 -0800285Probe *Context::get(const std::string &provider_name,
286 const std::string &probe_name) {
287 for (auto &p : probes_) {
288 if (p->provider_ == provider_name && p->name_ == probe_name)
289 return p.get();
290 }
291 return nullptr;
292}
293
Vicent Marti1a2ddac2016-05-01 13:41:33 +0200294bool Context::enable_probe(const std::string &probe_name,
295 const std::string &fn_name) {
Vicent Marti10436452016-05-04 16:58:51 +0200296 if (pid_stat_ && pid_stat_->is_stale())
Vicent Martieca47832016-05-01 12:53:46 +0200297 return false;
298
Yonghong Song24894572018-01-04 22:08:51 -0800299 // FIXME: we may have issues here if the context has two same probes's
300 // but different providers. For example, libc:setjmp and rtld:setjmp,
301 // libc:lll_futex_wait and rtld:lll_futex_wait.
302 Probe *found_probe = nullptr;
303 for (auto &p : probes_) {
304 if (p->name_ == probe_name) {
305 if (found_probe != nullptr) {
306 fprintf(stderr, "Two same-name probes (%s) but different providers\n",
307 probe_name.c_str());
308 return false;
309 }
310 found_probe = p.get();
311 }
312 }
313
314 if (found_probe != nullptr) {
315 found_probe->enable(fn_name);
316 return true;
317 }
318
319 return false;
Vicent Martieca47832016-05-01 12:53:46 +0200320}
321
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300322void Context::each(each_cb callback) {
323 for (const auto &probe : probes_) {
324 struct bcc_usdt info = {0};
325 info.provider = probe->provider().c_str();
326 info.bin_path = probe->bin_path().c_str();
327 info.name = probe->name().c_str();
328 info.semaphore = probe->semaphore();
329 info.num_locations = probe->num_locations();
330 info.num_arguments = probe->num_arguments();
331 callback(&info);
332 }
333}
334
Vicent Martieca47832016-05-01 12:53:46 +0200335void Context::each_uprobe(each_uprobe_cb callback) {
Vicent Marti10436452016-05-04 16:58:51 +0200336 for (auto &p : probes_) {
337 if (!p->enabled())
338 continue;
339
Sasha Goldshtein6e91a742016-10-06 18:18:18 +0300340 for (Location &loc : p->locations_) {
Yonghong Song24894572018-01-04 22:08:51 -0800341 callback(loc.bin_path_.c_str(), p->attached_to_->c_str(), loc.address_,
Vicent Marti1a2ddac2016-05-01 13:41:33 +0200342 pid_.value_or(-1));
Vicent Martieca47832016-05-01 12:53:46 +0200343 }
344 }
345}
346
Teng Qin137ee812017-08-25 16:29:16 -0700347Context::Context(const std::string &bin_path)
348 : mount_ns_instance_(new ProcMountNS(-1)), loaded_(false) {
Vicent Marti92598412016-04-28 19:42:55 +0200349 std::string full_path = resolve_bin_path(bin_path);
350 if (!full_path.empty()) {
Yonghong Song0ba15072017-07-21 22:13:20 -0700351 if (bcc_elf_foreach_usdt(full_path.c_str(), _each_probe, this) == 0) {
352 cmd_bin_path_ = full_path;
Vicent Marti92598412016-04-28 19:42:55 +0200353 loaded_ = true;
Yonghong Song0ba15072017-07-21 22:13:20 -0700354 }
Vicent Marti92598412016-04-28 19:42:55 +0200355 }
Teng Qin488c1192017-09-13 10:47:59 -0700356 for (const auto &probe : probes_)
357 probe->finalize_locations();
Vicent Marti92598412016-04-28 19:42:55 +0200358}
359
Vicent Marti96c1b8e2017-06-27 19:06:46 +0200360Context::Context(int pid) : pid_(pid), pid_stat_(pid),
361 mount_ns_instance_(new ProcMountNS(pid)), loaded_(false) {
Yonghong Song0ba15072017-07-21 22:13:20 -0700362 if (bcc_procutils_each_module(pid, _each_module, this) == 0) {
Teng Qin97562952017-09-18 13:36:49 -0700363 cmd_bin_path_ = ebpf::get_pid_exe(pid);
364 if (cmd_bin_path_.empty())
Yonghong Song0ba15072017-07-21 22:13:20 -0700365 return;
Yonghong Song0ba15072017-07-21 22:13:20 -0700366
Vicent Marti92598412016-04-28 19:42:55 +0200367 loaded_ = true;
Yonghong Song0ba15072017-07-21 22:13:20 -0700368 }
Teng Qin488c1192017-09-13 10:47:59 -0700369 for (const auto &probe : probes_)
370 probe->finalize_locations();
Vicent Marti92598412016-04-28 19:42:55 +0200371}
Vicent Martieca47832016-05-01 12:53:46 +0200372
Yonghong Songfead16a2018-01-10 10:43:28 -0800373Context::Context(int pid, const std::string &bin_path)
374 : pid_(pid), pid_stat_(pid),
375 mount_ns_instance_(new ProcMountNS(pid)), loaded_(false) {
376 std::string full_path = resolve_bin_path(bin_path);
377 if (!full_path.empty()) {
378 if (bcc_elf_foreach_usdt(full_path.c_str(), _each_probe, this) == 0) {
379 cmd_bin_path_ = ebpf::get_pid_exe(pid);
380 if (cmd_bin_path_.empty())
381 return;
382 loaded_ = true;
383 }
384 }
385 for (const auto &probe : probes_)
386 probe->finalize_locations();
387}
388
Vicent Martieca47832016-05-01 12:53:46 +0200389Context::~Context() {
Vicent Marti10436452016-05-04 16:58:51 +0200390 if (pid_stat_ && !pid_stat_->is_stale()) {
Vicent Marti040df7d2016-05-04 16:59:57 +0200391 for (auto &p : probes_) p->disable();
Vicent Martieca47832016-05-01 12:53:46 +0200392 }
393}
Vicent Martieca47832016-05-01 12:53:46 +0200394}
395
396extern "C" {
Vicent Martieca47832016-05-01 12:53:46 +0200397
Yonghong Songfead16a2018-01-10 10:43:28 -0800398void *bcc_usdt_new_frompid(int pid, const char *path) {
399 USDT::Context *ctx;
400
Javier Honduvilla Cotodcb9b9a2018-05-14 13:02:05 +0200401 if (!path) {
Yonghong Songfead16a2018-01-10 10:43:28 -0800402 ctx = new USDT::Context(pid);
Javier Honduvilla Cotodcb9b9a2018-05-14 13:02:05 +0200403 } else {
404 struct stat buffer;
405 if (strlen(path) >= 1 && path[0] != '/') {
406 fprintf(stderr, "HINT: Binary path should be absolute.\n\n");
407 return nullptr;
408 } else if (stat(path, &buffer) == -1) {
409 fprintf(stderr, "HINT: Specified binary doesn't exist.\n\n");
410 return nullptr;
411 }
Yonghong Songfead16a2018-01-10 10:43:28 -0800412 ctx = new USDT::Context(pid, path);
Javier Honduvilla Cotodcb9b9a2018-05-14 13:02:05 +0200413 }
Vicent Martieca47832016-05-01 12:53:46 +0200414 if (!ctx->loaded()) {
415 delete ctx;
416 return nullptr;
417 }
418 return static_cast<void *>(ctx);
419}
420
421void *bcc_usdt_new_frompath(const char *path) {
422 USDT::Context *ctx = new USDT::Context(path);
423 if (!ctx->loaded()) {
424 delete ctx;
425 return nullptr;
426 }
427 return static_cast<void *>(ctx);
428}
429
430void bcc_usdt_close(void *usdt) {
Teng Qine0604642018-02-09 17:49:47 -0800431 if (usdt) {
432 USDT::Context *ctx = static_cast<USDT::Context *>(usdt);
433 delete ctx;
434 }
Vicent Martieca47832016-05-01 12:53:46 +0200435}
436
Vicent Marti1a2ddac2016-05-01 13:41:33 +0200437int bcc_usdt_enable_probe(void *usdt, const char *probe_name,
438 const char *fn_name) {
Vicent Martieca47832016-05-01 12:53:46 +0200439 USDT::Context *ctx = static_cast<USDT::Context *>(usdt);
440 return ctx->enable_probe(probe_name, fn_name) ? 0 : -1;
441}
442
Yonghong Song0ba15072017-07-21 22:13:20 -0700443const char *bcc_usdt_genargs(void **usdt_array, int len) {
Brendan Gregg4f88a942016-07-22 17:11:51 -0700444 static std::string storage_;
Vicent Martieca47832016-05-01 12:53:46 +0200445 std::ostringstream stream;
Yonghong Song0ba15072017-07-21 22:13:20 -0700446
Brenden Blanco4cb1edb2017-08-16 11:26:14 -0700447 if (!len)
448 return "";
449
Yonghong Song0ba15072017-07-21 22:13:20 -0700450 stream << USDT::USDT_PROGRAM_HEADER;
451 // Generate genargs codes for an array of USDT Contexts.
452 //
453 // Each mnt_point + cmd_bin_path + probe_provider + probe_name
454 // uniquely identifies a probe.
455 std::unordered_set<std::string> generated_probes;
456 for (int i = 0; i < len; i++) {
457 USDT::Context *ctx = static_cast<USDT::Context *>(usdt_array[i]);
458
459 for (size_t j = 0; j < ctx->num_probes(); j++) {
460 USDT::Probe *p = ctx->get(j);
461 if (p->enabled()) {
462 std::string key = std::to_string(ctx->inode()) + "*"
463 + ctx->cmd_bin_path() + "*" + p->provider() + "*" + p->name();
464 if (generated_probes.find(key) != generated_probes.end())
465 continue;
466 if (!p->usdt_getarg(stream))
467 return nullptr;
468 generated_probes.insert(key);
469 }
470 }
471 }
Brendan Gregg4f88a942016-07-22 17:11:51 -0700472
473 storage_ = stream.str();
474 return storage_.c_str();
Vicent Martieca47832016-05-01 12:53:46 +0200475}
476
Teng Qin0615bff2016-09-28 08:19:40 -0700477const char *bcc_usdt_get_probe_argctype(
478 void *ctx, const char* probe_name, const int arg_index
479) {
480 USDT::Probe *p = static_cast<USDT::Context *>(ctx)->get(probe_name);
jeromemarchandb84714a2018-08-08 18:09:44 +0200481 if (p)
482 return p->get_arg_ctype(arg_index).c_str();
483 return "";
Teng Qin0615bff2016-09-28 08:19:40 -0700484}
485
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300486void bcc_usdt_foreach(void *usdt, bcc_usdt_cb callback) {
487 USDT::Context *ctx = static_cast<USDT::Context *>(usdt);
488 ctx->each(callback);
489}
490
Yonghong Song24894572018-01-04 22:08:51 -0800491int bcc_usdt_get_location(void *usdt, const char *provider_name,
492 const char *probe_name,
Sasha Goldshtein6e91a742016-10-06 18:18:18 +0300493 int index, struct bcc_usdt_location *location) {
Sasha Goldshtein8698bdb2017-02-19 20:29:45 +0000494 USDT::Context *ctx = static_cast<USDT::Context *>(usdt);
Yonghong Song24894572018-01-04 22:08:51 -0800495 USDT::Probe *probe = ctx->get(provider_name, probe_name);
Sasha Goldshtein8698bdb2017-02-19 20:29:45 +0000496 if (!probe)
497 return -1;
498 if (index < 0 || (size_t)index >= probe->num_locations())
499 return -1;
500 location->address = probe->address(index);
Yonghong Song24894572018-01-04 22:08:51 -0800501 location->bin_path = probe->location_bin_path(index);
Sasha Goldshtein8698bdb2017-02-19 20:29:45 +0000502 return 0;
Sasha Goldshtein6e91a742016-10-06 18:18:18 +0300503}
504
Yonghong Song24894572018-01-04 22:08:51 -0800505int bcc_usdt_get_argument(void *usdt, const char *provider_name,
506 const char *probe_name,
Sasha Goldshtein6e91a742016-10-06 18:18:18 +0300507 int location_index, int argument_index,
508 struct bcc_usdt_argument *argument) {
Sasha Goldshtein8698bdb2017-02-19 20:29:45 +0000509 USDT::Context *ctx = static_cast<USDT::Context *>(usdt);
Yonghong Song24894572018-01-04 22:08:51 -0800510 USDT::Probe *probe = ctx->get(provider_name, probe_name);
Sasha Goldshtein8698bdb2017-02-19 20:29:45 +0000511 if (!probe)
512 return -1;
513 if (argument_index < 0 || (size_t)argument_index >= probe->num_arguments())
514 return -1;
515 if (location_index < 0 || (size_t)location_index >= probe->num_locations())
516 return -1;
517 auto const &location = probe->location(location_index);
518 auto const &arg = location.arguments_[argument_index];
519 argument->size = arg.arg_size();
520 argument->valid = BCC_USDT_ARGUMENT_NONE;
521 if (arg.constant()) {
522 argument->valid |= BCC_USDT_ARGUMENT_CONSTANT;
523 argument->constant = *(arg.constant());
524 }
525 if (arg.deref_offset()) {
526 argument->valid |= BCC_USDT_ARGUMENT_DEREF_OFFSET;
527 argument->deref_offset = *(arg.deref_offset());
528 }
529 if (arg.deref_ident()) {
530 argument->valid |= BCC_USDT_ARGUMENT_DEREF_IDENT;
531 argument->deref_ident = arg.deref_ident()->c_str();
532 }
533 if (arg.base_register_name()) {
534 argument->valid |= BCC_USDT_ARGUMENT_BASE_REGISTER_NAME;
535 argument->base_register_name = arg.base_register_name()->c_str();
536 }
537 if (arg.index_register_name()) {
538 argument->valid |= BCC_USDT_ARGUMENT_INDEX_REGISTER_NAME;
539 argument->index_register_name = arg.index_register_name()->c_str();
540 }
541 if (arg.scale()) {
542 argument->valid |= BCC_USDT_ARGUMENT_SCALE;
543 argument->scale = *(arg.scale());
544 }
545 return 0;
Sasha Goldshtein6e91a742016-10-06 18:18:18 +0300546}
547
Vicent Martieca47832016-05-01 12:53:46 +0200548void bcc_usdt_foreach_uprobe(void *usdt, bcc_usdt_uprobe_cb callback) {
549 USDT::Context *ctx = static_cast<USDT::Context *>(usdt);
550 ctx->each_uprobe(callback);
551}
Vicent Marti0865f942016-04-27 16:57:58 +0200552}