Update #3665. --- trace/record/record-main-lttng.cc | 221 ++++++++++++++++++++++++++++++-------- trace/wscript | 12 ++- 2 files changed, 188 insertions(+), 45 deletions(-)
diff --git a/trace/record/record-main-lttng.cc b/trace/record/record-main-lttng.cc index dda57ef..4f7b5df 100644 --- a/trace/record/record-main-lttng.cc +++ b/trace/record/record-main-lttng.cc @@ -28,12 +28,18 @@ #include "client.h" +#include <rld-process.h> + #include <getopt.h> #include <cassert> +#include <cinttypes> #include <cstdio> #include <cstring> #include <iostream> +#include <map> +#include <string> +#include <vector> #define CTF_MAGIC 0xC1FC1FC1 #define TASK_RUNNING 0x0000 @@ -83,6 +89,9 @@ struct EventHeaderCompact { uint64_t ns; } __attribute__((__packed__)); +static const size_t kEventHeaderBits = + sizeof(EventHeaderCompact) * BITS_PER_CHAR; + struct EventRecordItem { EventHeaderCompact header; uint64_t data; @@ -160,6 +169,8 @@ class LTTNGClient : public Client { } } + void OpenDebug(const char* elf_file); + void Destroy() { Client::Destroy(); CloseStreamFiles(); @@ -180,6 +191,14 @@ class LTTNGClient : public Client { size_t cpu_count_ = 0; + std::string elf_file_; + + bool resolve_address_ = false; + + typedef std::map<uint64_t, std::vector<char>> AddressToLineMap; + + AddressToLineMap address_to_line_; + static rtems_record_client_status HandlerCaller(uint64_t bt, uint32_t cpu, rtems_record_event event, @@ -213,6 +232,10 @@ class LTTNGClient : public Client { void OpenStreamFiles(uint64_t data); void CloseStreamFiles(); + + AddressToLineMap::iterator AddAddressAsHexNumber(const ClientItem& item); + + AddressToLineMap::iterator ResolveAddress(const ClientItem& item); }; static uint32_t GetAPIIndexOfID(uint32_t id) { @@ -236,6 +259,11 @@ static const uint8_t kCPUPostfix[RTEMS_RECORD_CLIENT_MAXIMUM_CPU_COUNT][2] = { {'2', '5'}, {'2', '6'}, {'2', '7'}, {'2', '8'}, {'2', '9'}, {'3', '0'}, {'3', '1'}}; +void LTTNGClient::OpenDebug(const char* elf_file) { + elf_file_ = elf_file; + resolve_address_ = true; +} + void LTTNGClient::CopyThreadName(const ClientItem& item, size_t api_index, uint8_t* dst) const { @@ -260,15 +288,91 @@ void LTTNGClient::CopyThreadName(const ClientItem& item, } } +static bool IsCodeEvent(rtems_record_event event) { + switch (event) { + default: + return false; + case RTEMS_RECORD_CALLER: + case RTEMS_RECORD_LINE: + return true; + } +} + +LTTNGClient::AddressToLineMap::iterator LTTNGClient::AddAddressAsHexNumber( + const ClientItem& item) { + char hex[19]; + int n = std::snprintf(hex, sizeof(hex), "0x%" PRIx64, item.data); + assert(static_cast<size_t>(n) < sizeof(hex)); + std::vector<char> code(hex, hex + n + 1); + return address_to_line_.emplace(item.data, std::move(code)).first; +} + +LTTNGClient::AddressToLineMap::iterator LTTNGClient::ResolveAddress( + const ClientItem& item) { + AddressToLineMap::iterator it; + + if (resolve_address_) { + rld::process::arg_container args; + args.push_back("addr2line"); + args.push_back("-e"); + args.push_back(elf_file_); + args.push_back("-f"); + args.push_back("-p"); + args.push_back("-s"); + char hex[19]; + int n = std::snprintf(hex, sizeof(hex), "0x%" PRIx64, item.data); + assert(static_cast<size_t>(n) < sizeof(hex)); + args.push_back(hex); + + rld::process::tempfile out; + rld::process::tempfile err; + rld::process::status status = + rld::process::execute(args[0], args, out.name(), err.name()); + + if (status.type == rld::process::status::normal && status.code == 0) { + std::string str; + out.open(); + out.read(str); + std::vector<char> code(str.begin(), str.end()); + code.push_back('\0'); + it = address_to_line_.emplace(item.data, std::move(code)).first; + } else { + it = AddAddressAsHexNumber(item); + } + } else { + it = AddAddressAsHexNumber(item); + } + + return it; +} + void LTTNGClient::WriteRecordItem(PerCPUContext* pcpu, const ClientItem& item) { - pcpu->size_in_bits += kEventRecordItemBits; + if (IsCodeEvent(item.event)) { + EventHeaderCompact header; + header.id = COMPACT_HEADER_ID; + header.event_id = item.event; + header.ns = item.ns; + + auto it = address_to_line_.find(item.data); + if (it == address_to_line_.end()) { + it = ResolveAddress(item); + } + + pcpu->size_in_bits += (sizeof(header) + it->second.size()) * BITS_PER_CHAR; - EventRecordItem& ri = pcpu->record_item; - ri.header.ns = item.ns; - ri.header.event_id = item.event; - ri.data = item.data; + std::fwrite(&header, sizeof(header), 1, pcpu->event_stream); + std::fwrite(&(*it->second.begin()), it->second.size(), 1, + pcpu->event_stream); + } else { + pcpu->size_in_bits += kEventRecordItemBits; + + EventRecordItem& ri = pcpu->record_item; + ri.header.ns = item.ns; + ri.header.event_id = item.event; + ri.data = item.data; - std::fwrite(&ri, sizeof(ri), 1, pcpu->event_stream); + std::fwrite(&ri, sizeof(ri), 1, pcpu->event_stream); + } } void LTTNGClient::WriteSchedSwitch(PerCPUContext* pcpu, @@ -566,18 +670,33 @@ static void GenerateMetadata() { std::fwrite(kMetadata, sizeof(kMetadata) - 1, 1, f); for (int i = 0; i <= RTEMS_RECORD_LAST; ++i) { - std::fprintf(f, - "\n" - "event {\n" - "\tname = %s;\n" - "\tid = %i;\n" - "\tstream_id = 0;\n" - "\tfields := struct {\n" - "\t\txint64_t _data;\n" - "\t};\n" - "};\n", - rtems_record_event_text(static_cast<rtems_record_event>(i)), - i); + if (IsCodeEvent(static_cast<rtems_record_event>(i))) { + std::fprintf(f, + "\n" + "event {\n" + "\tname = %s;\n" + "\tid = %i;\n" + "\tstream_id = 0;\n" + "\tfields := struct {\n" + "\t\tstring _code;\n" + "\t};\n" + "};\n", + rtems_record_event_text(static_cast<rtems_record_event>(i)), + i); + } else { + std::fprintf(f, + "\n" + "event {\n" + "\tname = %s;\n" + "\tid = %i;\n" + "\tstream_id = 0;\n" + "\tfields := struct {\n" + "\t\txint64_t _data;\n" + "\t};\n" + "};\n", + rtems_record_event_text(static_cast<rtems_record_event>(i)), + i); + } } std::fclose(f); @@ -596,53 +715,58 @@ static const struct option kLongOpts[] = {{"help", 0, NULL, 'h'}, {NULL, 0, NULL, 0}}; static void Usage(char** argv) { - std::cout << argv[0] - << " [--host=HOST] [--port=PORT] [--limit=LIMIT] [INPUT-FILE]" - << std::endl - << std::endl - << "Mandatory arguments to long options are mandatory for short " - "options too." - << std::endl - << " -h, --help print this help text" << std::endl - << " -H, --host=HOST the host IPv4 address of the " - "record server" - << std::endl - << " -p, --port=PORT the TCP port of the record server" - << std::endl - << " -l, --limit=LIMIT limit in bytes to process" - << std::endl - << " INPUT-FILE the input file" << std::endl; + std::cout + << argv[0] + << " [--host=HOST] [--port=PORT] [--limit=LIMIT] [--elf=ELF] [INPUT-FILE]" + << std::endl + << std::endl + << "Mandatory arguments to long options are mandatory for short " + "options too." + << std::endl + << " -h, --help print this help text" << std::endl + << " -H, --host=HOST the host IPv4 address of the " + "record server" + << std::endl + << " -p, --port=PORT the TCP port of the record server" + << std::endl + << " -l, --limit=LIMIT limit in bytes to process" << std::endl + << " -e, --elf=ELF the ELF executable file" << std::endl + << " INPUT-FILE the input file" << std::endl; } int main(int argc, char** argv) { const char* host = "127.0.0.1"; uint16_t port = 1234; - const char* file = nullptr; + const char* elf_file = nullptr; + const char* input_file = nullptr; int opt; int longindex; - while ((opt = getopt_long(argc, argv, "hH:l:p:", &kLongOpts[0], + while ((opt = getopt_long(argc, argv, "e:hH:l:p:", &kLongOpts[0], &longindex)) != -1) { switch (opt) { + case 'e': + elf_file = optarg; + break; case 'h': Usage(argv); return 0; case 'H': host = optarg; break; - case 'p': - port = (uint16_t)strtoul(optarg, NULL, 0); - break; case 'l': client.set_limit(strtoull(optarg, NULL, 0)); break; + case 'p': + port = (uint16_t)strtoul(optarg, NULL, 0); + break; default: return 1; } } if (optind == argc - 1) { - file = argv[optind]; + input_file = argv[optind]; ++optind; } @@ -655,11 +779,18 @@ int main(int argc, char** argv) { return 1; } + rld::set_progname(argv[0]); + + int ec = 0; try { GenerateMetadata(); - if (file != nullptr) { - client.Open(file); + if (elf_file != nullptr) { + client.OpenDebug(elf_file); + } + + if (input_file != nullptr) { + client.Open(input_file); } else { client.Connect(host, port); } @@ -667,9 +798,13 @@ int main(int argc, char** argv) { std::signal(SIGINT, SignalHandler); client.Run(); client.Destroy(); + } catch (rld::error& e) { + std::cerr << "error: " << e.where << ": " << e.what << std::endl; + ec = 1; } catch (std::exception& e) { std::cerr << argv[0] << ": " << e.what() << std::endl; + ec = 2; } - return 0; + return ec; } diff --git a/trace/wscript b/trace/wscript index 36e7100..8999df9 100644 --- a/trace/wscript +++ b/trace/wscript @@ -43,6 +43,12 @@ def build(bld): # # Build flags. # + rtemstoolkit = '../rtemstoolkit' + conf['includes'] = [rtemstoolkit, + rtemstoolkit + '/elftoolchain/libelf', + rtemstoolkit + '/elftoolchain/libdwarf', + rtemstoolkit + '/elftoolchain/common', + 'record'] conf['warningflags'] = ['-Wall', '-Wextra', '-pedantic'] conf['optflags'] = bld.env.C_OPTS conf['cflags'] = ['-pipe', '-g'] + conf['optflags'] @@ -68,10 +74,12 @@ def build(bld): 'record/record-text.c', 'record/record-client-base.cc', 'record/record-main-lttng.cc'], - includes = ['record'], + includes = conf['includes'], defines = defines, cflags = conf['cflags'] + conf['warningflags'], - linkflags = conf['linkflags']) + cxxflags = conf['cxxflags'] + conf['warningflags'], + linkflags = conf['linkflags'], + use = modules) # # Build rtems-record-text -- 2.16.4 _______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel