in src/http/pprof_http_service.cpp [98:194]
static int extract_symbols_from_binary(std::map<uintptr_t, std::string> &addr_map,
const lib_info &lib_info)
{
SCOPED_LOG_TIMING(INFO, "load {}", lib_info.path);
std::string cmd = "nm -C -p ";
cmd.append(lib_info.path);
std::stringstream ss;
LOG_INFO("executing `{}`", cmd);
const int rc = utils::pipe_execute(cmd.c_str(), ss);
if (rc < 0) {
LOG_ERROR("fail to popen `{}`", cmd);
return -1;
}
std::string line;
while (std::getline(ss, line)) {
string_splitter sp(line.c_str(), ' ');
if (sp == NULL) {
continue;
}
char *endptr = NULL;
uintptr_t addr = strtoull(sp.field(), &endptr, 16);
if (*endptr != ' ') {
continue;
}
if (addr < lib_info.start_addr) {
addr = addr + lib_info.start_addr - lib_info.offset;
}
if (addr >= lib_info.end_addr) {
continue;
}
++sp;
if (sp == NULL) {
continue;
}
if (sp.length() != 1UL) {
continue;
}
// const char c = *sp.field();
++sp;
if (sp == NULL) {
continue;
}
const char *name_begin = sp.field();
if (utils::equals(name_begin, "typeinfo ", 9) || utils::equals(name_begin, "VTT ", 4) ||
utils::equals(name_begin, "vtable ", 7) || utils::equals(name_begin, "global ", 7) ||
utils::equals(name_begin, "guard ", 6)) {
addr_map[addr] = std::string();
continue;
}
const char *name_end = sp.field();
bool stop = false;
char last_char = '\0';
while (1) {
switch (*name_end) {
case 0:
case '\r':
case '\n':
stop = true;
break;
case '(':
case '<':
// \(.*\w\)[(<]... -> \1
// foo(..) -> foo
// foo<...>(...) -> foo
// a::b::foo(...) -> a::b::foo
// a::(b)::foo(...) -> a::(b)::foo
if (isalpha(last_char) || isdigit(last_char) || last_char == '_') {
stop = true;
}
default:
break;
}
if (stop) {
break;
}
last_char = *name_end++;
}
// If address conflicts, choose a shorter name (not necessarily to be
// T type in nm). This works fine because aliases often have more
// prefixes.
const size_t name_len = name_end - name_begin;
auto it = addr_map.find(addr);
if (it != addr_map.end()) {
if (name_len < it->second.size()) {
it->second.assign(name_begin, name_len);
}
} else {
addr_map[addr] = std::string(name_begin, name_len);
}
}
if (addr_map.find(lib_info.end_addr) == addr_map.end()) {
addr_map[lib_info.end_addr] = std::string();
}
return 0;
}