summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2019-09-06 09:29:12 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2019-09-10 11:01:00 +0200
commit5d80d0b2e1de9decb24c2d7ef481e4b63525595e (patch)
treef0a307679620a3687fa23cb007ffed9512d183b7
parentrecord: Windows compatibility (diff)
downloadrtems-tools-5d80d0b2e1de9decb24c2d7ef481e4b63525595e.tar.bz2
record: Optionally use LLVM to resolve addresses
Update #3665.
-rw-r--r--trace/record/record-main-lttng.cc218
-rw-r--r--trace/wscript10
2 files changed, 185 insertions, 43 deletions
diff --git a/trace/record/record-main-lttng.cc b/trace/record/record-main-lttng.cc
index dda57ef..4743bc1 100644
--- a/trace/record/record-main-lttng.cc
+++ b/trace/record/record-main-lttng.cc
@@ -26,14 +26,25 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
+#include "config.h"
+
#include "client.h"
#include <getopt.h>
#include <cassert>
+#include <cinttypes>
#include <cstdio>
#include <cstring>
#include <iostream>
+#include <map>
+#include <string>
+#include <vector>
+
+#ifdef HAVE_LLVM_DEBUGINFO_SYMBOLIZE_SYMBOLIZE_H
+#include <llvm/DebugInfo/Symbolize/Symbolize.h>
+#include <llvm/Support/Path.h>
+#endif
#define CTF_MAGIC 0xC1FC1FC1
#define TASK_RUNNING 0x0000
@@ -83,6 +94,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 +174,8 @@ class LTTNGClient : public Client {
}
}
+ void OpenExecutable(const char* elf_file);
+
void Destroy() {
Client::Destroy();
CloseStreamFiles();
@@ -180,6 +196,18 @@ class LTTNGClient : public Client {
size_t cpu_count_ = 0;
+#ifdef HAVE_LLVM_DEBUGINFO_SYMBOLIZE_SYMBOLIZE_H
+ llvm::symbolize::LLVMSymbolizer symbolizer_;
+#endif
+
+ 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 +241,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 +268,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::OpenExecutable(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 +297,87 @@ 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_FUNCTION_ENTRY:
+ case RTEMS_RECORD_FUNCTION_EXIT:
+ case RTEMS_RECORD_ISR_DISABLE:
+ case RTEMS_RECORD_ISR_ENABLE:
+ case RTEMS_RECORD_LINE:
+ case RTEMS_RECORD_THREAD_DISPATCH_DISABLE:
+ case RTEMS_RECORD_THREAD_DISPATCH_ENABLE:
+ 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) {
+#ifdef HAVE_LLVM_DEBUGINFO_SYMBOLIZE_SYMBOLIZE_H
+ if (resolve_address_) {
+ auto res_or_err = symbolizer_.symbolizeCode(elf_file_, item.data);
+
+ if (res_or_err) {
+ auto info = res_or_err.get();
+ std::string fn = info.FunctionName;
+ std::string str;
+
+ if (fn != "<invalid>") {
+ str += fn;
+ str += " at ";
+ }
+
+ str += llvm::sys::path::filename(info.FileName);
+ str += ":";
+ str += std::to_string(info.Line);
+ std::vector<char> code(str.begin(), str.end());
+ code.push_back('\0');
+ return address_to_line_.emplace(item.data, std::move(code)).first;
+ }
+ }
+#endif
+
+ return AddAddressAsHexNumber(item);
+}
+
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);
+ }
- EventRecordItem& ri = pcpu->record_item;
- ri.header.ns = item.ns;
- ri.header.event_id = item.event;
- ri.data = item.data;
+ pcpu->size_in_bits += (sizeof(header) + it->second.size()) * BITS_PER_CHAR;
- std::fwrite(&ri, sizeof(ri), 1, pcpu->event_stream);
+ 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);
+ }
}
void LTTNGClient::WriteSchedSwitch(PerCPUContext* pcpu,
@@ -566,18 +675,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 +720,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;
}
@@ -658,8 +787,12 @@ int main(int argc, char** argv) {
try {
GenerateMetadata();
- if (file != nullptr) {
- client.Open(file);
+ if (elf_file != nullptr) {
+ client.OpenExecutable(elf_file);
+ }
+
+ if (input_file != nullptr) {
+ client.Open(input_file);
} else {
client.Connect(host, port);
}
@@ -669,6 +802,7 @@ int main(int argc, char** argv) {
client.Destroy();
} catch (std::exception& e) {
std::cerr << argv[0] << ": " << e.what() << std::endl;
+ return 1;
}
return 0;
diff --git a/trace/wscript b/trace/wscript
index a2124ad..7335c8f 100644
--- a/trace/wscript
+++ b/trace/wscript
@@ -33,7 +33,10 @@ def options(opt):
def configure(conf):
conf.load('compiler_c')
conf.load('compiler_cxx')
+ conf.check_cxx(lib = 'LLVM', mandatory=False)
+ conf.check(header_name='llvm/DebugInfo/Symbolize/Symbolize.h', features='cxx', mandatory=False)
conf.check_cxx(lib = 'ws2_32', mandatory=False)
+ conf.write_config_header('config.h')
def build(bld):
#
@@ -44,13 +47,17 @@ def build(bld):
#
# Build flags.
#
+ conf['includes'] = ['.', 'record']
conf['warningflags'] = ['-Wall', '-Wextra', '-pedantic']
conf['optflags'] = bld.env.C_OPTS
conf['cflags'] = ['-pipe', '-g'] + conf['optflags']
conf['cxxflags'] = ['-std=c++11'] + conf['cflags']
+ conf['linkflags'] = ['-g']
conf['lib'] = []
if bld.env.LIB_WS2_32:
conf['lib'].extend(bld.env.LIB_WS2_32)
+ if bld.env.LIB_LLVM:
+ conf['lib'].extend(bld.env.LIB_LLVM)
#
# The list of defines
@@ -66,10 +73,11 @@ 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'],
cxxflags = conf['cxxflags'] + conf['warningflags'],
+ linkflags = conf['linkflags'],
lib = conf['lib'])
def tags(ctx):