[PATCH] record: Use addr2line to link to the source code
Sebastian Huber
sebastian.huber at embedded-brains.de
Fri Sep 6 07:29:12 UTC 2019
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
More information about the devel
mailing list