Home | History | Annotate | Download | only in usdt
      1 /*
      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  */
     16 #include <algorithm>
     17 #include <cstring>
     18 #include <sstream>
     19 #include <unordered_set>
     20 
     21 #include <fcntl.h>
     22 #include <sys/stat.h>
     23 #include <sys/types.h>
     24 #include <unistd.h>
     25 
     26 #include "bcc_elf.h"
     27 #include "bcc_proc.h"
     28 #include "common.h"
     29 #include "usdt.h"
     30 #include "vendor/tinyformat.hpp"
     31 #include "bcc_usdt.h"
     32 
     33 namespace USDT {
     34 
     35 Location::Location(uint64_t addr, const std::string &bin_path, const char *arg_fmt)
     36     : address_(addr),
     37       bin_path_(bin_path) {
     38 
     39 #ifdef __aarch64__
     40   ArgumentParser_aarch64 parser(arg_fmt);
     41 #elif __powerpc64__
     42   ArgumentParser_powerpc64 parser(arg_fmt);
     43 #else
     44   ArgumentParser_x64 parser(arg_fmt);
     45 #endif
     46   while (!parser.done()) {
     47     Argument arg;
     48     if (!parser.parse(&arg))
     49       continue;
     50     arguments_.push_back(std::move(arg));
     51   }
     52 }
     53 
     54 Probe::Probe(const char *bin_path, const char *provider, const char *name,
     55              uint64_t semaphore, const optional<int> &pid, ProcMountNS *ns)
     56     : bin_path_(bin_path),
     57       provider_(provider),
     58       name_(name),
     59       semaphore_(semaphore),
     60       pid_(pid),
     61       mount_ns_(ns) {}
     62 
     63 bool 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];
     69 }
     70 
     71 bool Probe::resolve_global_address(uint64_t *global, const std::string &bin_path,
     72                                    const uint64_t addr) {
     73   if (in_shared_object(bin_path)) {
     74     return (pid_ &&
     75             !bcc_resolve_global_addr(*pid_, bin_path.c_str(), addr, global));
     76   }
     77 
     78   *global = addr;
     79   return true;
     80 }
     81 
     82 bool Probe::add_to_semaphore(int16_t val) {
     83   assert(pid_);
     84 
     85   if (!attached_semaphore_) {
     86     uint64_t addr;
     87     if (!resolve_global_address(&addr, bin_path_, semaphore_))
     88       return false;
     89     attached_semaphore_ = addr;
     90   }
     91 
     92   off_t address = static_cast<off_t>(attached_semaphore_.value());
     93 
     94   std::string procmem = tfm::format("/proc/%d/mem", pid_.value());
     95   int memfd = ::open(procmem.c_str(), O_RDWR);
     96   if (memfd < 0)
     97     return false;
     98 
     99   int16_t original;
    100 
    101   if (::lseek(memfd, address, SEEK_SET) < 0 ||
    102       ::read(memfd, &original, 2) != 2) {
    103     ::close(memfd);
    104     return false;
    105   }
    106 
    107   original = original + val;
    108 
    109   if (::lseek(memfd, address, SEEK_SET) < 0 ||
    110       ::write(memfd, &original, 2) != 2) {
    111     ::close(memfd);
    112     return false;
    113   }
    114 
    115   ::close(memfd);
    116   return true;
    117 }
    118 
    119 bool Probe::enable(const std::string &fn_name) {
    120   if (attached_to_)
    121     return false;
    122 
    123   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;
    132   return true;
    133 }
    134 
    135 bool Probe::disable() {
    136   if (!attached_to_)
    137     return false;
    138 
    139   attached_to_ = nullopt;
    140 
    141   if (need_enable()) {
    142     assert(pid_);
    143     return add_to_semaphore(-1);
    144   }
    145   return true;
    146 }
    147 
    148 std::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 ||
    153         std::abs(candidate->arg_size()) > std::abs(largest->arg_size()))
    154       largest = candidate;
    155   }
    156 
    157   assert(largest);
    158   return largest->ctype();
    159 }
    160 
    161 bool Probe::usdt_getarg(std::ostream &stream) {
    162   if (!attached_to_ || attached_to_->empty())
    163     return false;
    164 
    165   return usdt_getarg(stream, attached_to_.value());
    166 }
    167 
    168 bool Probe::usdt_getarg(std::ostream &stream, const std::string& probe_func) {
    169   const size_t arg_count = locations_[0].arguments_.size();
    170 
    171   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);
    176     std::string cptr = tfm::format("*((%s *)dest)", ctype);
    177 
    178     tfm::format(stream,
    179                 "static __always_inline int _bpf_readarg_%s_%d("
    180                 "struct pt_regs *ctx, void *dest, size_t len) {\n"
    181                 "  if (len != sizeof(%s)) return -1;\n",
    182                 probe_func, arg_n + 1, ctype);
    183 
    184     if (locations_.size() == 1) {
    185       Location &location = locations_.front();
    186       stream << "  ";
    187       if (!location.arguments_[arg_n].assign_to_local(stream, cptr, location.bin_path_,
    188                                                       pid_))
    189         return false;
    190       stream << "\n  return 0;\n}\n";
    191     } else {
    192       stream << "  switch(PT_REGS_IP(ctx)) {\n";
    193       for (Location &location : locations_) {
    194         uint64_t global_address;
    195 
    196         if (!resolve_global_address(&global_address, location.bin_path_,
    197                                     location.address_))
    198           return false;
    199 
    200         tfm::format(stream, "  case 0x%xULL: ", global_address);
    201         if (!location.arguments_[arg_n].assign_to_local(stream, cptr, location.bin_path_,
    202                                                         pid_))
    203           return false;
    204 
    205         stream << " return 0;\n";
    206       }
    207       stream << "  }\n";
    208       stream << "  return -1;\n}\n";
    209     }
    210   }
    211   return true;
    212 }
    213 
    214 void Probe::add_location(uint64_t addr, const std::string &bin_path, const char *fmt) {
    215   locations_.emplace_back(addr, bin_path, fmt);
    216 }
    217 
    218 void Probe::finalize_locations() {
    219   std::sort(locations_.begin(), locations_.end(),
    220             [](const Location &a, const Location &b) {
    221               return a.bin_path_ < b.bin_path_ || a.address_ < b.address_;
    222             });
    223   auto last = std::unique(locations_.begin(), locations_.end(),
    224                           [](const Location &a, const Location &b) {
    225                             return a.bin_path_ == b.bin_path_ && a.address_ == b.address_;
    226                           });
    227   locations_.erase(last, locations_.end());
    228 }
    229 
    230 void 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 
    236 int Context::_each_module(const char *modpath, uint64_t, uint64_t, uint64_t,
    237                           bool, void *p) {
    238   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?*/) {
    243     ProcMountNSGuard g(ctx->mount_ns_instance_.get());
    244     bcc_elf_foreach_usdt(modpath, _each_probe, p);
    245   }
    246   return 0;
    247 }
    248 
    249 void Context::add_probe(const char *binpath, const struct bcc_elf_usdt *probe) {
    250   for (auto &p : probes_) {
    251     if (p->provider_ == probe->provider && p->name_ == probe->name) {
    252       p->add_location(probe->pc, binpath, probe->arg_fmt);
    253       return;
    254     }
    255   }
    256 
    257   probes_.emplace_back(
    258       new Probe(binpath, probe->provider, probe->name, probe->semaphore, pid_,
    259 	mount_ns_instance_.get()));
    260   probes_.back()->add_location(probe->pc, binpath, probe->arg_fmt);
    261 }
    262 
    263 std::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);
    269   } else if (char *which_so = bcc_procutils_which_so(bin_path.c_str(), 0)) {
    270     result = which_so;
    271     ::free(which_so);
    272   }
    273 
    274   return result;
    275 }
    276 
    277 Probe *Context::get(const std::string &probe_name) {
    278   for (auto &p : probes_) {
    279     if (p->name_ == probe_name)
    280       return p.get();
    281   }
    282   return nullptr;
    283 }
    284 
    285 Probe *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 
    294 bool Context::enable_probe(const std::string &probe_name,
    295                            const std::string &fn_name) {
    296   if (pid_stat_ && pid_stat_->is_stale())
    297     return false;
    298 
    299   // 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     return found_probe->enable(fn_name);
    316 
    317   return false;
    318 }
    319 
    320 void Context::each(each_cb callback) {
    321   for (const auto &probe : probes_) {
    322     struct bcc_usdt info = {0};
    323     info.provider = probe->provider().c_str();
    324     info.bin_path = probe->bin_path().c_str();
    325     info.name = probe->name().c_str();
    326     info.semaphore = probe->semaphore();
    327     info.num_locations = probe->num_locations();
    328     info.num_arguments = probe->num_arguments();
    329     callback(&info);
    330   }
    331 }
    332 
    333 void Context::each_uprobe(each_uprobe_cb callback) {
    334   for (auto &p : probes_) {
    335     if (!p->enabled())
    336       continue;
    337 
    338     for (Location &loc : p->locations_) {
    339       callback(loc.bin_path_.c_str(), p->attached_to_->c_str(), loc.address_,
    340                pid_.value_or(-1));
    341     }
    342   }
    343 }
    344 
    345 Context::Context(const std::string &bin_path)
    346     : mount_ns_instance_(new ProcMountNS(-1)), loaded_(false) {
    347   std::string full_path = resolve_bin_path(bin_path);
    348   if (!full_path.empty()) {
    349     if (bcc_elf_foreach_usdt(full_path.c_str(), _each_probe, this) == 0) {
    350       cmd_bin_path_ = full_path;
    351       loaded_ = true;
    352     }
    353   }
    354   for (const auto &probe : probes_)
    355     probe->finalize_locations();
    356 }
    357 
    358 Context::Context(int pid) : pid_(pid), pid_stat_(pid),
    359   mount_ns_instance_(new ProcMountNS(pid)), loaded_(false) {
    360   if (bcc_procutils_each_module(pid, _each_module, this) == 0) {
    361     cmd_bin_path_ = ebpf::get_pid_exe(pid);
    362     if (cmd_bin_path_.empty())
    363       return;
    364 
    365     loaded_ = true;
    366   }
    367   for (const auto &probe : probes_)
    368     probe->finalize_locations();
    369 }
    370 
    371 Context::Context(int pid, const std::string &bin_path)
    372     : pid_(pid), pid_stat_(pid),
    373       mount_ns_instance_(new ProcMountNS(pid)), loaded_(false) {
    374   std::string full_path = resolve_bin_path(bin_path);
    375   if (!full_path.empty()) {
    376     if (bcc_elf_foreach_usdt(full_path.c_str(), _each_probe, this) == 0) {
    377       cmd_bin_path_ = ebpf::get_pid_exe(pid);
    378       if (cmd_bin_path_.empty())
    379         return;
    380       loaded_ = true;
    381     }
    382   }
    383   for (const auto &probe : probes_)
    384     probe->finalize_locations();
    385 }
    386 
    387 Context::~Context() {
    388   if (pid_stat_ && !pid_stat_->is_stale()) {
    389     for (auto &p : probes_) p->disable();
    390   }
    391 }
    392 }
    393 
    394 extern "C" {
    395 
    396 void *bcc_usdt_new_frompid(int pid, const char *path) {
    397   USDT::Context *ctx;
    398 
    399   if (!path) {
    400     ctx = new USDT::Context(pid);
    401   } else {
    402     struct stat buffer;
    403     if (strlen(path) >= 1 && path[0] != '/') {
    404       fprintf(stderr, "HINT: Binary path should be absolute.\n\n");
    405       return nullptr;
    406     } else if (stat(path, &buffer) == -1) {
    407       fprintf(stderr, "HINT: Specified binary doesn't exist.\n\n");
    408       return nullptr;
    409     }
    410     ctx = new USDT::Context(pid, path);
    411   }
    412   if (!ctx->loaded()) {
    413     delete ctx;
    414     return nullptr;
    415   }
    416   return static_cast<void *>(ctx);
    417 }
    418 
    419 void *bcc_usdt_new_frompath(const char *path) {
    420   USDT::Context *ctx = new USDT::Context(path);
    421   if (!ctx->loaded()) {
    422     delete ctx;
    423     return nullptr;
    424   }
    425   return static_cast<void *>(ctx);
    426 }
    427 
    428 void bcc_usdt_close(void *usdt) {
    429   if (usdt) {
    430     USDT::Context *ctx = static_cast<USDT::Context *>(usdt);
    431     delete ctx;
    432   }
    433 }
    434 
    435 int bcc_usdt_enable_probe(void *usdt, const char *probe_name,
    436                           const char *fn_name) {
    437   USDT::Context *ctx = static_cast<USDT::Context *>(usdt);
    438   return ctx->enable_probe(probe_name, fn_name) ? 0 : -1;
    439 }
    440 
    441 const char *bcc_usdt_genargs(void **usdt_array, int len) {
    442   static std::string storage_;
    443   std::ostringstream stream;
    444 
    445   if (!len)
    446     return "";
    447 
    448   stream << USDT::USDT_PROGRAM_HEADER;
    449   // Generate genargs codes for an array of USDT Contexts.
    450   //
    451   // Each mnt_point + cmd_bin_path + probe_provider + probe_name
    452   // uniquely identifies a probe.
    453   std::unordered_set<std::string> generated_probes;
    454   for (int i = 0; i < len; i++) {
    455     USDT::Context *ctx = static_cast<USDT::Context *>(usdt_array[i]);
    456 
    457     for (size_t j = 0; j < ctx->num_probes(); j++) {
    458       USDT::Probe *p = ctx->get(j);
    459       if (p->enabled()) {
    460         std::string key = std::to_string(ctx->inode()) + "*"
    461           + ctx->cmd_bin_path() + "*" + p->provider() + "*" + p->name();
    462         if (generated_probes.find(key) != generated_probes.end())
    463           continue;
    464         if (!p->usdt_getarg(stream))
    465           return nullptr;
    466         generated_probes.insert(key);
    467       }
    468     }
    469   }
    470 
    471   storage_ = stream.str();
    472   return storage_.c_str();
    473 }
    474 
    475 const char *bcc_usdt_get_probe_argctype(
    476   void *ctx, const char* probe_name, const int arg_index
    477 ) {
    478   USDT::Probe *p = static_cast<USDT::Context *>(ctx)->get(probe_name);
    479   if (p)
    480     return p->get_arg_ctype(arg_index).c_str();
    481   return "";
    482 }
    483 
    484 void bcc_usdt_foreach(void *usdt, bcc_usdt_cb callback) {
    485   USDT::Context *ctx = static_cast<USDT::Context *>(usdt);
    486   ctx->each(callback);
    487 }
    488 
    489 int bcc_usdt_get_location(void *usdt, const char *provider_name,
    490                           const char *probe_name,
    491                           int index, struct bcc_usdt_location *location) {
    492   USDT::Context *ctx = static_cast<USDT::Context *>(usdt);
    493   USDT::Probe *probe = ctx->get(provider_name, probe_name);
    494   if (!probe)
    495     return -1;
    496   if (index < 0 || (size_t)index >= probe->num_locations())
    497     return -1;
    498   location->address = probe->address(index);
    499   location->bin_path = probe->location_bin_path(index);
    500   return 0;
    501 }
    502 
    503 int bcc_usdt_get_argument(void *usdt, const char *provider_name,
    504                           const char *probe_name,
    505                           int location_index, int argument_index,
    506                           struct bcc_usdt_argument *argument) {
    507   USDT::Context *ctx = static_cast<USDT::Context *>(usdt);
    508   USDT::Probe *probe = ctx->get(provider_name, probe_name);
    509   if (!probe)
    510     return -1;
    511   if (argument_index < 0 || (size_t)argument_index >= probe->num_arguments())
    512     return -1;
    513   if (location_index < 0 || (size_t)location_index >= probe->num_locations())
    514     return -1;
    515   auto const &location = probe->location(location_index);
    516   auto const &arg = location.arguments_[argument_index];
    517   argument->size = arg.arg_size();
    518   argument->valid = BCC_USDT_ARGUMENT_NONE;
    519   if (arg.constant()) {
    520     argument->valid |= BCC_USDT_ARGUMENT_CONSTANT;
    521     argument->constant = *(arg.constant());
    522   }
    523   if (arg.deref_offset()) {
    524     argument->valid |= BCC_USDT_ARGUMENT_DEREF_OFFSET;
    525     argument->deref_offset = *(arg.deref_offset());
    526   }
    527   if (arg.deref_ident()) {
    528     argument->valid |= BCC_USDT_ARGUMENT_DEREF_IDENT;
    529     argument->deref_ident = arg.deref_ident()->c_str();
    530   }
    531   if (arg.base_register_name()) {
    532     argument->valid |= BCC_USDT_ARGUMENT_BASE_REGISTER_NAME;
    533     argument->base_register_name = arg.base_register_name()->c_str();
    534   }
    535   if (arg.index_register_name()) {
    536     argument->valid |= BCC_USDT_ARGUMENT_INDEX_REGISTER_NAME;
    537     argument->index_register_name = arg.index_register_name()->c_str();
    538   }
    539   if (arg.scale()) {
    540     argument->valid |= BCC_USDT_ARGUMENT_SCALE;
    541     argument->scale = *(arg.scale());
    542   }
    543   return 0;
    544 }
    545 
    546 void bcc_usdt_foreach_uprobe(void *usdt, bcc_usdt_uprobe_cb callback) {
    547   USDT::Context *ctx = static_cast<USDT::Context *>(usdt);
    548   ctx->each_uprobe(callback);
    549 }
    550 }
    551