2 * Copyright 2012 Facebook, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 #include "folly/experimental/symbolizer/Symbolizer.h"
20 #include <boost/regex.hpp>
21 #include <glog/logging.h>
23 #include "folly/experimental/symbolizer/Elf.h"
24 #include "folly/experimental/symbolizer/Dwarf.h"
25 #include "folly/Range.h"
26 #include "folly/FBString.h"
27 #include "folly/String.h"
28 #include "folly/experimental/Gen.h"
29 #include "folly/experimental/FileGen.h"
30 #include "folly/experimental/StringGen.h"
33 namespace symbolizer {
36 StringPiece sp(const boost::csub_match& m) {
37 return StringPiece(m.first, m.second);
40 uint64_t fromHex(StringPiece s) {
41 // Make a copy; we need a null-terminated string for strtoull
42 fbstring str(s.data(), s.size());
43 const char* p = str.c_str();
45 uint64_t val = strtoull(p, &end, 16);
46 CHECK(*p != '\0' && *end == '\0');
58 bool Symbolizer::symbolize(uintptr_t address, StringPiece& symbolName,
59 Dwarf::LocationInfo& location) {
61 location = Dwarf::LocationInfo();
63 // Entry in /proc/self/maps
64 static const boost::regex mapLineRegex(
65 "([[:xdigit:]]+)-([[:xdigit:]]+)" // from-to
67 "[\\w-]+" // permissions
69 "([[:xdigit:]]+)" // offset
71 "[[:xdigit:]]+:[[:xdigit:]]+" // device, minor:major
80 bool error = gen::byLine("/proc/self/maps") | gen::eachAs<StringPiece>() |
81 [&] (StringPiece line) -> bool {
82 CHECK(boost::regex_match(line.begin(), line.end(), match, mapLineRegex));
83 uint64_t begin = fromHex(sp(match[1]));
84 uint64_t end = fromHex(sp(match[2]));
85 uint64_t fileOffset = fromHex(sp(match[3]));
86 if (fileOffset != 0) {
87 return true; // main mapping starts at 0
90 if (begin <= address && address < end) {
91 foundFile.begin = begin;
93 foundFile.name.assign(match[4].first, match[4].second);
104 auto& elfFile = getFile(foundFile.name);
106 uintptr_t origAddress = address - foundFile.begin + elfFile.getBaseAddress();
108 auto sym = elfFile.getDefinitionByAddress(origAddress);
113 auto name = elfFile.getSymbolName(sym);
118 Dwarf(&elfFile).findAddress(origAddress, location);
122 ElfFile& Symbolizer::getFile(const std::string& name) {
123 auto pos = elfFiles_.find(name);
124 if (pos != elfFiles_.end()) {
128 return elfFiles_.insert(
129 std::make_pair(name, ElfFile(name.c_str()))).first->second;
132 void Symbolizer::write(std::ostream& out, uintptr_t address,
133 StringPiece symbolName,
134 const Dwarf::LocationInfo& location) {
136 sprintf(buf, "%#18jx", address);
139 if (!symbolName.empty()) {
140 out << " " << demangle(symbolName.toString().c_str());
143 if (location.hasFileAndLine) {
144 file = location.file.toString();
145 out << " " << file << ":" << location.line;
148 std::string mainFile;
149 if (location.hasMainFile) {
150 mainFile = location.mainFile.toString();
151 if (!location.hasFileAndLine || file != mainFile) {
152 out << "\n (compiling "
153 << location.mainFile << ")";
162 } // namespace symbolizer