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>
22 #include "folly/experimental/symbolizer/Elf.h"
23 #include "folly/experimental/symbolizer/Dwarf.h"
24 #include "glog/logging.h"
25 #include "folly/Range.h"
26 #include "folly/FBString.h"
27 #include "folly/String.h"
28 #include "folly/experimental/io/Stream.h"
31 namespace symbolizer {
34 folly::StringPiece sp(const boost::csub_match& m) {
35 return folly::StringPiece(m.first, m.second);
38 uint64_t fromHex(folly::StringPiece s) {
39 // Make a copy; we need a null-terminated string for strtoull
40 folly::fbstring str(s.data(), s.size());
41 const char* p = str.c_str();
43 uint64_t val = strtoull(p, &end, 16);
44 CHECK(*p != '\0' && *end == '\0');
56 bool Symbolizer::symbolize(uintptr_t address, folly::StringPiece& symbolName,
57 Dwarf::LocationInfo& location) {
59 location = Dwarf::LocationInfo();
61 // Entry in /proc/self/maps
62 static const boost::regex mapLineRegex(
63 "([[:xdigit:]]+)-([[:xdigit:]]+)" // from-to
65 "[\\w-]+" // permissions
67 "([[:xdigit:]]+)" // offset
69 "[[:xdigit:]]+:[[:xdigit:]]+" // device, minor:major
79 for (auto& byteLine : folly::byLine("/proc/self/maps")) {
80 folly::StringPiece line(byteLine);
81 CHECK(boost::regex_match(line.begin(), line.end(), match, mapLineRegex));
82 uint64_t begin = fromHex(sp(match[1]));
83 uint64_t end = fromHex(sp(match[2]));
84 uint64_t fileOffset = fromHex(sp(match[3]));
85 if (fileOffset != 0) {
86 continue; // main mapping starts at 0
89 if (begin <= address && address < end) {
91 foundFile.begin = begin;
93 foundFile.name.assign(match[4].first, match[4].second);
102 auto& elfFile = getFile(foundFile.name);
104 uintptr_t origAddress = address - foundFile.begin + elfFile.getBaseAddress();
106 auto sym = elfFile.getDefinitionByAddress(origAddress);
111 auto name = elfFile.getSymbolName(sym);
116 Dwarf(&elfFile).findAddress(origAddress, location);
120 ElfFile& Symbolizer::getFile(const std::string& name) {
121 auto pos = elfFiles_.find(name);
122 if (pos != elfFiles_.end()) {
126 return elfFiles_.insert(
127 std::make_pair(name, ElfFile(name.c_str()))).first->second;
130 void Symbolizer::write(std::ostream& out, uintptr_t address,
131 folly::StringPiece symbolName,
132 const Dwarf::LocationInfo& location) {
134 sprintf(buf, "%#18jx", address);
137 if (!symbolName.empty()) {
138 out << " " << folly::demangle(symbolName.toString().c_str());
141 if (location.hasFileAndLine) {
142 file = location.file.toString();
143 out << " " << file << ":" << location.line;
146 std::string mainFile;
147 if (location.hasMainFile) {
148 mainFile = location.mainFile.toString();
149 if (!location.hasFileAndLine || file != mainFile) {
150 out << "\n (compiling "
151 << location.mainFile << ")";
160 } // namespace symbolizer
161 } // namespace facebook