----- Am 6. Sep 2019 um 18:06 schrieb Sebastian Huber
sebastian.hu...@embedded-brains.de:
> ----- Am 6. Sep 2019 um 11:09 schrieb Sebastian Huber
> sebastian.hu...@embedded-brains.de:
>
>> On 06/09/2019 09:26, Sebastian Huber wrote:
>>> On 06/09/2019 09:01, Chris Johns wrote:
>>>> On 6/9/19 4:20 pm, Sebastian Huber wrote:
>>>>> Hello,
>>>>>
>>>>> I tried the rtems-addr2line on ARM and SPARC. On SPARC it seems to
>>>>> work fine,
>>>>> however, on ARM I get this:
>>>>>
>>>>> rtems-addr2line -e
>>>>> build/arm-rtems5-xilinx_zynq_a9_qemu-everything/media01.exe
>>>>> 0x0000135a
>>>>> /home/EB/sebastian_h/git-rtems-5/c/src/lib/libbsp/arm/xilinx-zynq/../../../../../../bsps/arm/shared/irq/irq-gic.c:264
>>>>>
>>>>>
>>>>>
>>>>> addr2line -e
>>>>> build/arm-rtems5-xilinx_zynq_a9_qemu-everything/media01.exe 0000135a
>>>>> /scratch/git-rtems-libbsd/build/arm-rtems5-xilinx_zynq_a9_qemu-everything/../../testsuite/include/rtems/bsd/test/default-network-init.h:179
>>>>>
>>>>>
>>>>>
>>>>> The GNU tool is right. It is also considerably faster.
>>>> I would hope it is faster and exact. It has had many years of work on it,
>>>> written in C and not a means to test a C++ framework so we can grow an
>>>> ecosystem. I have stated its purpose before. I am perplexed by the
>>>> intent of
>>>> this statement.
>>>>
>>>> If you want to compare performance I suggest you try the elftools one?
>>>> There is
>>>> one. It is not built because GNU provides one and good one.
>>>>
>>>> Also be-careful as the exec call is not as fast as Linux on all the
>>>> hosts we
>>>> support.
>>>
>>> That the GNU tool is faster was just an observation.
>>>
>>> Do we have a working library solution to get from an address to the
>>> source line/function? I don't have time to debug the DWARF support code
>>> at the moment.
>>>
>>> I have a working solution using "addr2line" and rld::process::execute().
>>
>> Thanks for the hint to the elftoolchain:
>>
>> https://github.com/elftoolchain/elftoolchain/blob/trunk/addr2line/addr2line.c
>>
>> To me it looks pretty complicated. It should be possible to refactor
>> this code to use it as a library, e.g. call translate() for each address
>> you need the source information.
>>
>> I tried to debug the rld get_source() problem for more than two hours
>> and the elftoolchain code looks similar. I am not sure what to do.
>
> Another option is to use the LLVM infrastructure:
>
> https://github.com/llvm-mirror/llvm/blob/master/tools/llvm-symbolizer/llvm-symbolizer.cpp
>
> From a first glance, this looks like the way to go.
Attached is a patch which uses the LLVM library to get an addr2line
functionality. The code to resolve an address is very easy (item.data is the
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);
LLVM has also support for command line arguments, file handling, etc.
From 3245f52d5f1cf8496daf53acc921e8b7594b375c Mon Sep 17 00:00:00 2001
From: Sebastian Huber <sebastian.hu...@embedded-brains.de>
Date: Fri, 6 Sep 2019 09:29:12 +0200
Subject: [PATCH] record: Use LLVM to link to the source code
Update #3665.
---
trace/record/record-main-lttng.cc | 213 ++++++++++++++++++++++++++++++--------
trace/wscript | 7 +-
2 files changed, 175 insertions(+), 45 deletions(-)
diff --git a/trace/record/record-main-lttng.cc b/trace/record/record-main-lttng.cc
index dda57ef..d921143 100644
--- a/trace/record/record-main-lttng.cc
+++ b/trace/record/record-main-lttng.cc
@@ -31,9 +31,16 @@
#include <getopt.h>
#include <cassert>
+#include <cinttypes>
#include <cstdio>
#include <cstring>
#include <iostream>
+#include <map>
+#include <string>
+#include <vector>
+
+#include <llvm/DebugInfo/Symbolize/Symbolize.h>
+#include <llvm/Support/Path.h>
#define CTF_MAGIC 0xC1FC1FC1
#define TASK_RUNNING 0x0000
@@ -83,6 +90,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 +170,8 @@ class LTTNGClient : public Client {
}
}
+ void OpenDebug(const char* elf_file);
+
void Destroy() {
Client::Destroy();
CloseStreamFiles();
@@ -180,6 +192,16 @@ class LTTNGClient : public Client {
size_t cpu_count_ = 0;
+ llvm::symbolize::LLVMSymbolizer symbolizer_;
+
+ 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 +235,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 +262,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 +291,85 @@ 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_) {
+ 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');
+ 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 +667,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 +712,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 +776,16 @@ int main(int argc, char** argv) {
return 1;
}
+ 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);
}
@@ -669,7 +795,8 @@ int main(int argc, char** argv) {
client.Destroy();
} 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 9bac9b9..39cff1c 100644
--- a/trace/wscript
+++ b/trace/wscript
@@ -43,6 +43,7 @@ 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']
@@ -62,10 +63,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['cflags'] + conf['warningflags'],
+ linkflags = conf['linkflags'],
+ lib = 'LLVM')
def tags(ctx):
ctx.exec_command('etags $(find . -name \*.[sSch])', shell = True)
--
2.16.4
_______________________________________________
devel mailing list
devel@rtems.org
http://lists.rtems.org/mailman/listinfo/devel