146756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris/*
246756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris * Copyright (C) 2014 The Android Open Source Project
346756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris *
446756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris * Licensed under the Apache License, Version 2.0 (the "License");
546756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris * you may not use this file except in compliance with the License.
646756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris * You may obtain a copy of the License at
746756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris *
846756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris *      http://www.apache.org/licenses/LICENSE-2.0
946756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris *
1046756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris * Unless required by applicable law or agreed to in writing, software
1146756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris * distributed under the License is distributed on an "AS IS" BASIS,
1246756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1346756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris * See the License for the specific language governing permissions and
1446756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris * limitations under the License.
1546756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris */
1646756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris
17cfd5b080af8de527d768f0ff7902c26af8d49307Mark Salyzyn#define LOG_TAG "backtrace-map"
18cfd5b080af8de527d768f0ff7902c26af8d49307Mark Salyzyn
1946756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris#include <ctype.h>
20ec2ff8c176d795656e69aecfce9650db40bef60bChih-Hung Hsieh#include <inttypes.h>
212c43cff01d1271be451671567955158629b23670Christopher Ferris#include <stdint.h>
2246756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris#include <sys/types.h>
2346756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris#include <unistd.h>
2446756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris
2530f991f251940be3ed11566fb71139852286f68aMark Salyzyn#include <log/log.h>
2630f991f251940be3ed11566fb71139852286f68aMark Salyzyn
27e1415a5c3b3e279fd6cfb6a7ee73ddc98bbec2aeElliott Hughes#include <android-base/stringprintf.h>
28e1415a5c3b3e279fd6cfb6a7ee73ddc98bbec2aeElliott Hughes#include <backtrace/Backtrace.h>
2946756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris#include <backtrace/BacktraceMap.h>
30e1415a5c3b3e279fd6cfb6a7ee73ddc98bbec2aeElliott Hughes#include <backtrace/backtrace_constants.h>
3146756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris
32df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris#include "thread_utils.h"
33df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris
34e1415a5c3b3e279fd6cfb6a7ee73ddc98bbec2aeElliott Hughesusing android::base::StringPrintf;
35e1415a5c3b3e279fd6cfb6a7ee73ddc98bbec2aeElliott Hughes
36e1415a5c3b3e279fd6cfb6a7ee73ddc98bbec2aeElliott Hughesstd::string backtrace_map_t::Name() const {
37e1415a5c3b3e279fd6cfb6a7ee73ddc98bbec2aeElliott Hughes  if (!name.empty()) return name;
38e1415a5c3b3e279fd6cfb6a7ee73ddc98bbec2aeElliott Hughes  if (start == 0 && end == 0) return "";
39e1415a5c3b3e279fd6cfb6a7ee73ddc98bbec2aeElliott Hughes  return StringPrintf("<anonymous:%" PRIPTR ">", start);
40e1415a5c3b3e279fd6cfb6a7ee73ddc98bbec2aeElliott Hughes}
41e1415a5c3b3e279fd6cfb6a7ee73ddc98bbec2aeElliott Hughes
4246756821c4fe238f12a6e5ea18c356398f8d8795Christopher FerrisBacktraceMap::BacktraceMap(pid_t pid) : pid_(pid) {
4346756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris  if (pid_ < 0) {
4446756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris    pid_ = getpid();
4546756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris  }
4646756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris}
4746756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris
4846756821c4fe238f12a6e5ea18c356398f8d8795Christopher FerrisBacktraceMap::~BacktraceMap() {
4946756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris}
5046756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris
517937a36c8e24ef2dc5105a2a6b67f395934b2e2fChristopher Ferrisvoid BacktraceMap::FillIn(uint64_t addr, backtrace_map_t* map) {
523a14004c7f521cf2ca6dfea182fa7441e77c97e7Christopher Ferris  ScopedBacktraceMapIteratorLock lock(this);
53b7de5f542925216dbb8b7124260d2915570598d1Christopher Ferris  for (auto it = begin(); it != end(); ++it) {
54b7de5f542925216dbb8b7124260d2915570598d1Christopher Ferris    const backtrace_map_t* entry = *it;
55b7de5f542925216dbb8b7124260d2915570598d1Christopher Ferris    if (addr >= entry->start && addr < entry->end) {
56b7de5f542925216dbb8b7124260d2915570598d1Christopher Ferris      *map = *entry;
5712385e3ad085aa1ac06c26529b32b688503a9fcfChristopher Ferris      return;
5846756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris    }
5946756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris  }
6012385e3ad085aa1ac06c26529b32b688503a9fcfChristopher Ferris  *map = {};
6146756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris}
6246756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris
6346756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferrisbool BacktraceMap::ParseLine(const char* line, backtrace_map_t* map) {
64ec2ff8c176d795656e69aecfce9650db40bef60bChih-Hung Hsieh  uint64_t start;
65ec2ff8c176d795656e69aecfce9650db40bef60bChih-Hung Hsieh  uint64_t end;
6646756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris  char permissions[5];
6746756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris  int name_pos;
6846756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris
6946756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris#if defined(__APPLE__)
7046756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris// Mac OS vmmap(1) output:
7146756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris// __TEXT                 0009f000-000a1000 [    8K     8K] r-x/rwx SM=COW  /Volumes/android/dalvik-dev/out/host/darwin-x86/bin/libcorkscrew_test\n
7246756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris// 012345678901234567890123456789012345678901234567890123456789
7346756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris// 0         1         2         3         4         5
74ec2ff8c176d795656e69aecfce9650db40bef60bChih-Hung Hsieh  if (sscanf(line, "%*21c %" SCNx64 "-%" SCNx64 " [%*13c] %3c/%*3c SM=%*3c  %n",
7546756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris             &start, &end, permissions, &name_pos) != 3) {
7646756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris#else
7746756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris// Linux /proc/<pid>/maps lines:
7846756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419   /system/lib/libcomposer.so\n
7946756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris// 012345678901234567890123456789012345678901234567890123456789
8046756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris// 0         1         2         3         4         5
81ec2ff8c176d795656e69aecfce9650db40bef60bChih-Hung Hsieh  if (sscanf(line, "%" SCNx64 "-%" SCNx64 " %4s %*x %*x:%*x %*d %n",
8246756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris             &start, &end, permissions, &name_pos) != 3) {
8346756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris#endif
8446756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris    return false;
8546756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris  }
8646756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris
8746756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris  map->start = start;
8846756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris  map->end = end;
8946756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris  map->flags = PROT_NONE;
9046756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris  if (permissions[0] == 'r') {
9146756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris    map->flags |= PROT_READ;
9246756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris  }
9346756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris  if (permissions[1] == 'w') {
9446756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris    map->flags |= PROT_WRITE;
9546756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris  }
9646756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris  if (permissions[2] == 'x') {
9746756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris    map->flags |= PROT_EXEC;
9846756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris  }
9946756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris
10046756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris  map->name = line+name_pos;
10146756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris  if (!map->name.empty() && map->name[map->name.length()-1] == '\n') {
10246756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris    map->name.erase(map->name.length()-1);
10346756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris  }
10446756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris
10546756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris  ALOGV("Parsed map: start=%p, end=%p, flags=%x, name=%s",
106f4b0b7971c0333b7331c2f54384af5de0260ae75Colin Cross        reinterpret_cast<void*>(map->start), reinterpret_cast<void*>(map->end),
107f4b0b7971c0333b7331c2f54384af5de0260ae75Colin Cross        map->flags, map->name.c_str());
10846756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris  return true;
10946756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris}
11046756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris
11146756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferrisbool BacktraceMap::Build() {
11246756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris#if defined(__APPLE__)
11346756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris  char cmd[sizeof(pid_t)*3 + sizeof("vmmap -w -resident -submap -allSplitLibs -interleaved ") + 1];
11446756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris#else
11546756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris  char path[sizeof(pid_t)*3 + sizeof("/proc//maps") + 1];
11646756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris#endif
11746756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris  char line[1024];
11846756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris
11946756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris#if defined(__APPLE__)
12046756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris  // cmd is guaranteed to always be big enough to hold this string.
121b8c72957f072a687a4fb99dd7f2423d3f86e70d2Christopher Ferris  snprintf(cmd, sizeof(cmd), "vmmap -w -resident -submap -allSplitLibs -interleaved %d", pid_);
12246756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris  FILE* fp = popen(cmd, "r");
12346756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris#else
12446756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris  // path is guaranteed to always be big enough to hold this string.
125b8c72957f072a687a4fb99dd7f2423d3f86e70d2Christopher Ferris  snprintf(path, sizeof(path), "/proc/%d/maps", pid_);
12646756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris  FILE* fp = fopen(path, "r");
12746756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris#endif
1282c43cff01d1271be451671567955158629b23670Christopher Ferris  if (fp == nullptr) {
12946756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris    return false;
13046756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris  }
13146756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris
13246756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris  while(fgets(line, sizeof(line), fp)) {
13346756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris    backtrace_map_t map;
13446756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris    if (ParseLine(line, &map)) {
13546756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris      maps_.push_back(map);
13646756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris    }
13746756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris  }
13846756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris#if defined(__APPLE__)
13946756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris  pclose(fp);
14046756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris#else
14146756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris  fclose(fp);
14246756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris#endif
14346756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris
14446756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris  return true;
14546756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris}
146df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris
147df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris#if defined(__APPLE__)
148df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris// Corkscrew and libunwind don't compile on the mac, so create a generic
149df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris// map object.
1505b439eaf938aa27b7db04225694be7d2a25af477Colin CrossBacktraceMap* BacktraceMap::Create(pid_t pid, bool /*uncached*/) {
151df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris  BacktraceMap* map = new BacktraceMap(pid);
152df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris  if (!map->Build()) {
153df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris    delete map;
1542c43cff01d1271be451671567955158629b23670Christopher Ferris    return nullptr;
155df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris  }
156df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris  return map;
157df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris}
158df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris#endif
159