Merge "libprocinfo: add functions reading process map file."

This commit is contained in:
Yabin Cui 2018-05-15 18:01:56 +00:00 committed by Gerrit Code Review
commit 0f837fe8ca
16 changed files with 2460 additions and 331 deletions

View file

@ -91,7 +91,10 @@ cc_library {
"libdexfile",
],
static_libs: ["libcutils"],
static_libs: [
"libcutils",
"libprocinfo",
],
// libdexfile will eventually properly export headers, for now
// include these directly.

View file

@ -28,6 +28,9 @@
#include <backtrace/Backtrace.h>
#include <backtrace/BacktraceMap.h>
#include <backtrace/backtrace_constants.h>
#if defined(__linux__)
#include <procinfo/process_map.h>
#endif
#include "thread_utils.h"
@ -60,27 +63,19 @@ void BacktraceMap::FillIn(uint64_t addr, backtrace_map_t* map) {
*map = {};
}
bool BacktraceMap::ParseLine(const char* line, backtrace_map_t* map) {
#if defined(__APPLE__)
static bool ParseLine(const char* line, backtrace_map_t* map) {
uint64_t start;
uint64_t end;
char permissions[5];
int name_pos;
#if defined(__APPLE__)
// Mac OS vmmap(1) output:
// __TEXT 0009f000-000a1000 [ 8K 8K] r-x/rwx SM=COW /Volumes/android/dalvik-dev/out/host/darwin-x86/bin/libcorkscrew_test\n
// 012345678901234567890123456789012345678901234567890123456789
// 0 1 2 3 4 5
if (sscanf(line, "%*21c %" SCNx64 "-%" SCNx64 " [%*13c] %3c/%*3c SM=%*3c %n",
&start, &end, permissions, &name_pos) != 3) {
#else
// Linux /proc/<pid>/maps lines:
// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /system/lib/libcomposer.so\n
// 012345678901234567890123456789012345678901234567890123456789
// 0 1 2 3 4 5
if (sscanf(line, "%" SCNx64 "-%" SCNx64 " %4s %*x %*x:%*x %*d %n",
&start, &end, permissions, &name_pos) != 3) {
#endif
return false;
}
@ -107,24 +102,15 @@ bool BacktraceMap::ParseLine(const char* line, backtrace_map_t* map) {
map->flags, map->name.c_str());
return true;
}
#endif // defined(__APPLE__)
bool BacktraceMap::Build() {
#if defined(__APPLE__)
char cmd[sizeof(pid_t)*3 + sizeof("vmmap -w -resident -submap -allSplitLibs -interleaved ") + 1];
#else
char path[sizeof(pid_t)*3 + sizeof("/proc//maps") + 1];
#endif
char line[1024];
#if defined(__APPLE__)
// cmd is guaranteed to always be big enough to hold this string.
snprintf(cmd, sizeof(cmd), "vmmap -w -resident -submap -allSplitLibs -interleaved %d", pid_);
FILE* fp = popen(cmd, "r");
#else
// path is guaranteed to always be big enough to hold this string.
snprintf(path, sizeof(path), "/proc/%d/maps", pid_);
FILE* fp = fopen(path, "r");
#endif
if (fp == nullptr) {
return false;
}
@ -135,13 +121,19 @@ bool BacktraceMap::Build() {
maps_.push_back(map);
}
}
#if defined(__APPLE__)
pclose(fp);
#else
fclose(fp);
#endif
return true;
#else
return android::procinfo::ReadProcessMaps(
pid_, [&](uint64_t start, uint64_t end, uint16_t flags, uint64_t, const char* name) {
maps_.resize(maps_.size() + 1);
backtrace_map_t& map = maps_.back();
map.start = start;
map.end = end;
map.flags = flags;
map.name = name;
});
#endif
}
#if defined(__APPLE__)

View file

@ -169,8 +169,6 @@ public:
virtual uint64_t GetLoadBias(size_t /* index */) { return 0; }
virtual bool ParseLine(const char* line, backtrace_map_t* map);
pid_t pid_;
std::deque<backtrace_map_t> maps_;
std::vector<std::string> suffixes_to_ignore_;

View file

@ -29,7 +29,6 @@ cc_library {
"HeapWalker.cpp",
"LeakFolding.cpp",
"LeakPipe.cpp",
"LineBuffer.cpp",
"MemUnreachable.cpp",
"ProcessMappings.cpp",
"PtracerThread.cpp",
@ -38,6 +37,7 @@ cc_library {
static_libs: [
"libc_malloc_debug_backtrace",
"libprocinfo",
],
// Only need this for arm since libc++ uses its own unwind code that
// doesn't mix with the other default unwind code.

View file

@ -1,66 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Copied from system/extras/memory_replay/LineBuffer.cpp
// TODO(ccross): find a way to share between libmemunreachable and memory_replay?
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include "LineBuffer.h"
namespace android {
LineBuffer::LineBuffer(int fd, char* buffer, size_t buffer_len)
: fd_(fd), buffer_(buffer), buffer_len_(buffer_len) {}
bool LineBuffer::GetLine(char** line, size_t* line_len) {
while (true) {
if (bytes_ > 0) {
char* newline = reinterpret_cast<char*>(memchr(buffer_ + start_, '\n', bytes_));
if (newline != nullptr) {
*newline = '\0';
*line = buffer_ + start_;
start_ = newline - buffer_ + 1;
bytes_ -= newline - *line + 1;
*line_len = newline - *line;
return true;
}
}
if (start_ > 0) {
// Didn't find anything, copy the current to the front of the buffer.
memmove(buffer_, buffer_ + start_, bytes_);
start_ = 0;
}
ssize_t bytes = TEMP_FAILURE_RETRY(read(fd_, buffer_ + bytes_, buffer_len_ - bytes_ - 1));
if (bytes <= 0) {
if (bytes_ > 0) {
// The read data might not contain a nul terminator, so add one.
buffer_[bytes_] = '\0';
*line = buffer_ + start_;
*line_len = bytes_;
bytes_ = 0;
start_ = 0;
return true;
}
return false;
}
bytes_ += bytes;
}
}
} // namespace android

View file

@ -1,40 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _LIBMEMUNREACHABLE_LINE_BUFFER_H
#define _LIBMEMUNREACHABLE_LINE_BUFFER_H
#include <stdint.h>
namespace android {
class LineBuffer {
public:
LineBuffer(int fd, char* buffer, size_t buffer_len);
bool GetLine(char** line, size_t* line_len);
private:
int fd_;
char* buffer_ = nullptr;
size_t buffer_len_ = 0;
size_t start_ = 0;
size_t bytes_ = 0;
};
} // namespace android
#endif // _LIBMEMUNREACHABLE_LINE_BUFFER_H

View file

@ -14,21 +14,30 @@
* limitations under the License.
*/
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <string.h>
#include <unistd.h>
#include <android-base/unique_fd.h>
#include <procinfo/process_map.h>
#include "LineBuffer.h"
#include "ProcessMappings.h"
#include "log.h"
namespace android {
// This function is not re-entrant since it uses a static buffer for
// the line data.
struct ReadMapCallback {
ReadMapCallback(allocator::vector<Mapping>& mappings) : mappings_(mappings) {}
void operator()(uint64_t start, uint64_t end, uint16_t flags, uint64_t, const char* name) const {
mappings_.emplace_back(start, end, flags & PROT_READ, flags & PROT_WRITE, flags & PROT_EXEC,
name);
}
allocator::vector<Mapping>& mappings_;
};
bool ProcessMappings(pid_t pid, allocator::vector<Mapping>& mappings) {
char map_buffer[1024];
snprintf(map_buffer, sizeof(map_buffer), "/proc/%d/maps", pid);
@ -36,35 +45,13 @@ bool ProcessMappings(pid_t pid, allocator::vector<Mapping>& mappings) {
if (fd == -1) {
return false;
}
LineBuffer line_buf(fd, map_buffer, sizeof(map_buffer));
char* line;
size_t line_len;
while (line_buf.GetLine(&line, &line_len)) {
int name_pos;
char perms[5];
Mapping mapping{};
if (sscanf(line, "%" SCNxPTR "-%" SCNxPTR " %4s %*x %*x:%*x %*d %n", &mapping.begin,
&mapping.end, perms, &name_pos) == 3) {
if (perms[0] == 'r') {
mapping.read = true;
}
if (perms[1] == 'w') {
mapping.write = true;
}
if (perms[2] == 'x') {
mapping.execute = true;
}
if (perms[3] == 'p') {
mapping.priv = true;
}
if ((size_t)name_pos < line_len) {
strlcpy(mapping.name, line + name_pos, sizeof(mapping.name));
}
mappings.emplace_back(mapping);
}
allocator::string content(mappings.get_allocator());
ssize_t n;
while ((n = TEMP_FAILURE_RETRY(read(fd, map_buffer, sizeof(map_buffer)))) > 0) {
content.append(map_buffer, n);
}
return true;
ReadMapCallback callback(mappings);
return android::procinfo::ReadMapFileContent(&content[0], callback);
}
} // namespace android

View file

@ -17,6 +17,8 @@
#ifndef LIBMEMUNREACHABLE_PROCESS_MAPPING_H_
#define LIBMEMUNREACHABLE_PROCESS_MAPPING_H_
#include <string.h>
#include "Allocator.h"
namespace android {
@ -27,8 +29,13 @@ struct Mapping {
bool read;
bool write;
bool execute;
bool priv;
char name[96];
Mapping() {}
Mapping(uintptr_t begin, uintptr_t end, bool read, bool write, bool execute, const char* name)
: begin(begin), end(end), read(read), write(write), execute(execute) {
strlcpy(this->name, name, sizeof(this->name));
}
};
// This function is not re-entrant since it uses a static buffer for

View file

@ -59,6 +59,7 @@ cc_test {
host_supported: true,
srcs: [
"process_test.cpp",
"process_map_test.cpp",
],
target: {
darwin: {
@ -84,5 +85,45 @@ cc_test {
},
},
data: [
"testdata/*",
],
test_suites: ["device-tests"],
}
cc_benchmark {
name: "libprocinfo_benchmark",
defaults: ["libprocinfo_defaults"],
host_supported: true,
srcs: [
"process_map_benchmark.cpp",
],
target: {
darwin: {
enabled: false,
},
windows: {
enabled: false,
},
},
shared_libs: [
"libbacktrace",
"libbase",
"libprocinfo",
"libunwindstack",
],
compile_multilib: "both",
multilib: {
lib32: {
suffix: "32",
},
lib64: {
suffix: "64",
},
},
data: [
"testdata/*",
],
}

View file

@ -0,0 +1,151 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <functional>
#include <string>
#include <android-base/file.h>
namespace android {
namespace procinfo {
template <class CallbackType>
bool ReadMapFileContent(char* content, const CallbackType& callback) {
uint64_t start_addr;
uint64_t end_addr;
uint16_t flags;
uint64_t pgoff;
char* next_line = content;
char* p;
auto pass_space = [&]() {
if (*p != ' ') {
return false;
}
while (*p == ' ') {
p++;
}
return true;
};
auto pass_xdigit = [&]() {
if (!isxdigit(*p)) {
return false;
}
do {
p++;
} while (isxdigit(*p));
return true;
};
while (next_line != nullptr && *next_line != '\0') {
p = next_line;
next_line = strchr(next_line, '\n');
if (next_line != nullptr) {
*next_line = '\0';
next_line++;
}
// Parse line like: 00400000-00409000 r-xp 00000000 fc:00 426998 /usr/lib/gvfs/gvfsd-http
char* end;
// start_addr
start_addr = strtoull(p, &end, 16);
if (end == p || *end != '-') {
return false;
}
p = end + 1;
// end_addr
end_addr = strtoull(p, &end, 16);
if (end == p) {
return false;
}
p = end;
if (!pass_space()) {
return false;
}
// flags
flags = 0;
if (*p == 'r') {
flags |= PROT_READ;
} else if (*p != '-') {
return false;
}
p++;
if (*p == 'w') {
flags |= PROT_WRITE;
} else if (*p != '-') {
return false;
}
p++;
if (*p == 'x') {
flags |= PROT_EXEC;
} else if (*p != '-') {
return false;
}
p++;
if (*p != 'p' && *p != 's') {
return false;
}
p++;
if (!pass_space()) {
return false;
}
// pgoff
pgoff = strtoull(p, &end, 16);
if (end == p) {
return false;
}
p = end;
if (!pass_space()) {
return false;
}
// major:minor
if (!pass_xdigit() || *p++ != ':' || !pass_xdigit() || !pass_space()) {
return false;
}
// inode
if (!pass_xdigit() || (*p != '\0' && !pass_space())) {
return false;
}
// filename
callback(start_addr, end_addr, flags, pgoff, p);
}
return true;
}
inline bool ReadMapFile(
const std::string& map_file,
const std::function<void(uint64_t, uint64_t, uint16_t, uint64_t, const char*)>& callback) {
std::string content;
if (!android::base::ReadFileToString(map_file, &content)) {
return false;
}
return ReadMapFileContent(&content[0], callback);
}
inline bool ReadProcessMaps(
pid_t pid,
const std::function<void(uint64_t, uint64_t, uint16_t, uint64_t, const char*)>& callback) {
return ReadMapFile("/proc/" + std::to_string(pid) + "/maps", callback);
}
} /* namespace procinfo */
} /* namespace android */

View file

@ -0,0 +1,85 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <procinfo/process_map.h>
#include <string.h>
#include <string>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <backtrace/BacktraceMap.h>
#include <unwindstack/Maps.h>
#include <benchmark/benchmark.h>
struct MapInfo {
uint64_t start;
uint64_t end;
uint16_t flags;
uint64_t pgoff;
const std::string name;
MapInfo(uint64_t start, uint64_t end, uint16_t flags, uint64_t pgoff, const char* name)
: start(start), end(end), flags(flags), pgoff(pgoff), name(name) {}
};
static void BM_ReadMapFile(benchmark::State& state) {
std::string map_file = android::base::GetExecutableDirectory() + "/testdata/maps";
for (auto _ : state) {
std::vector<MapInfo> maps;
android::procinfo::ReadMapFile(
map_file, [&](uint64_t start, uint64_t end, uint16_t flags, uint64_t pgoff,
const char* name) { maps.emplace_back(start, end, flags, pgoff, name); });
CHECK_EQ(maps.size(), 2043u);
}
}
BENCHMARK(BM_ReadMapFile);
static void BM_unwindstack_FileMaps(benchmark::State& state) {
std::string map_file = android::base::GetExecutableDirectory() + "/testdata/maps";
for (auto _ : state) {
unwindstack::FileMaps maps(map_file);
maps.Parse();
CHECK_EQ(maps.Total(), 2043u);
}
}
BENCHMARK(BM_unwindstack_FileMaps);
static void BM_unwindstack_BufferMaps(benchmark::State& state) {
std::string map_file = android::base::GetExecutableDirectory() + "/testdata/maps";
std::string content;
CHECK(android::base::ReadFileToString(map_file, &content));
for (auto _ : state) {
unwindstack::BufferMaps maps(content.c_str());
maps.Parse();
CHECK_EQ(maps.Total(), 2043u);
}
}
BENCHMARK(BM_unwindstack_BufferMaps);
static void BM_backtrace_BacktraceMap(benchmark::State& state) {
pid_t pid = getpid();
for (auto _ : state) {
BacktraceMap* map = BacktraceMap::Create(pid, true);
CHECK(map != nullptr);
delete map;
}
}
BENCHMARK(BM_backtrace_BacktraceMap);
BENCHMARK_MAIN();

View file

@ -0,0 +1,60 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <procinfo/process_map.h>
#include <string>
#include <android-base/file.h>
#include <gtest/gtest.h>
struct MapInfo {
uint64_t start;
uint64_t end;
uint16_t flags;
uint64_t pgoff;
const std::string name;
MapInfo(uint64_t start, uint64_t end, uint16_t flags, uint64_t pgoff, const char* name)
: start(start), end(end), flags(flags), pgoff(pgoff), name(name) {}
};
TEST(process_map, smoke) {
std::string map_file = android::base::GetExecutableDirectory() + "/testdata/maps";
std::vector<MapInfo> maps;
ASSERT_TRUE(android::procinfo::ReadMapFile(
map_file, [&](uint64_t start, uint64_t end, uint16_t flags, uint64_t pgoff,
const char* name) { maps.emplace_back(start, end, flags, pgoff, name); }));
ASSERT_EQ(2043u, maps.size());
ASSERT_EQ(maps[0].start, 0x12c00000ULL);
ASSERT_EQ(maps[0].end, 0x2ac00000ULL);
ASSERT_EQ(maps[0].flags, PROT_READ | PROT_WRITE);
ASSERT_EQ(maps[0].pgoff, 0ULL);
ASSERT_EQ(maps[0].name, "/dev/ashmem/dalvik-main space (region space) (deleted)");
ASSERT_EQ(maps[876].start, 0x70e6c4f000ULL);
ASSERT_EQ(maps[876].end, 0x70e6c6b000ULL);
ASSERT_EQ(maps[876].flags, PROT_READ | PROT_EXEC);
ASSERT_EQ(maps[876].pgoff, 0ULL);
ASSERT_EQ(maps[876].name, "/system/lib64/libutils.so");
ASSERT_EQ(maps[1260].start, 0x70e96fa000ULL);
ASSERT_EQ(maps[1260].end, 0x70e96fb000ULL);
ASSERT_EQ(maps[1260].flags, PROT_READ);
ASSERT_EQ(maps[1260].pgoff, 0ULL);
ASSERT_EQ(maps[1260].name,
"/dev/ashmem/dalvik-classes.dex extracted in memory from "
"/data/app/com.google.sample.tunnel-HGGRU03Gu1Mwkf_-RnFmvw==/base.apk (deleted)");
}

2043
libprocinfo/testdata/maps vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -110,6 +110,10 @@ cc_library {
},
},
static_libs: [
"libprocinfo",
],
shared_libs: [
"libbase",
"libdexfile",

View file

@ -24,6 +24,7 @@
#include <unistd.h>
#include <android-base/unique_fd.h>
#include <procinfo/process_map.h>
#include <algorithm>
#include <cctype>
@ -57,150 +58,16 @@ MapInfo* Maps::Find(uint64_t pc) {
return nullptr;
}
// Assumes that line does not end in '\n'.
static MapInfo* InternalParseLine(const char* line) {
// Do not use a sscanf implementation since it is not performant.
// Example linux /proc/<pid>/maps lines:
// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /system/lib/libcomposer.so
char* str;
const char* old_str = line;
uint64_t start = strtoull(old_str, &str, 16);
if (old_str == str || *str++ != '-') {
return nullptr;
}
old_str = str;
uint64_t end = strtoull(old_str, &str, 16);
if (old_str == str || !std::isspace(*str++)) {
return nullptr;
}
while (std::isspace(*str)) {
str++;
}
// Parse permissions data.
if (*str == '\0') {
return nullptr;
}
uint16_t flags = 0;
if (*str == 'r') {
flags |= PROT_READ;
} else if (*str != '-') {
return nullptr;
}
str++;
if (*str == 'w') {
flags |= PROT_WRITE;
} else if (*str != '-') {
return nullptr;
}
str++;
if (*str == 'x') {
flags |= PROT_EXEC;
} else if (*str != '-') {
return nullptr;
}
str++;
if (*str != 'p' && *str != 's') {
return nullptr;
}
str++;
if (!std::isspace(*str++)) {
return nullptr;
}
old_str = str;
uint64_t offset = strtoull(old_str, &str, 16);
if (old_str == str || !std::isspace(*str)) {
return nullptr;
}
// Ignore the 00:00 values.
old_str = str;
(void)strtoull(old_str, &str, 16);
if (old_str == str || *str++ != ':') {
return nullptr;
}
if (std::isspace(*str)) {
return nullptr;
}
// Skip the inode.
old_str = str;
(void)strtoull(str, &str, 16);
if (old_str == str || !std::isspace(*str++)) {
return nullptr;
}
// Skip decimal digit.
old_str = str;
(void)strtoull(old_str, &str, 10);
if (old_str == str || (!std::isspace(*str) && *str != '\0')) {
return nullptr;
}
while (std::isspace(*str)) {
str++;
}
if (*str == '\0') {
return new MapInfo(start, end, offset, flags, "");
}
// Save the name data.
std::string name(str);
// Mark a device map in /dev/ and not in /dev/ashmem/ specially.
if (name.substr(0, 5) == "/dev/" && name.substr(5, 7) != "ashmem/") {
flags |= MAPS_FLAGS_DEVICE_MAP;
}
return new MapInfo(start, end, offset, flags, name);
}
bool Maps::Parse() {
int fd = open(GetMapsFile().c_str(), O_RDONLY | O_CLOEXEC);
if (fd == -1) {
return false;
}
bool return_value = true;
char buffer[2048];
size_t leftover = 0;
while (true) {
ssize_t bytes = read(fd, &buffer[leftover], 2048 - leftover);
if (bytes == -1) {
return_value = false;
break;
}
if (bytes == 0) {
break;
}
bytes += leftover;
char* line = buffer;
while (bytes > 0) {
char* newline = static_cast<char*>(memchr(line, '\n', bytes));
if (newline == nullptr) {
memmove(buffer, line, bytes);
break;
}
*newline = '\0';
MapInfo* map_info = InternalParseLine(line);
if (map_info == nullptr) {
return_value = false;
break;
}
maps_.push_back(map_info);
bytes -= newline - line + 1;
line = newline + 1;
}
leftover = bytes;
}
close(fd);
return return_value;
return android::procinfo::ReadMapFile(
GetMapsFile(),
[&](uint64_t start, uint64_t end, uint16_t flags, uint64_t pgoff, const char* name) {
// Mark a device map in /dev/ and not in /dev/ashmem/ specially.
if (strncmp(name, "/dev/", 5) == 0 && strncmp(name + 5, "ashmem/", 7) != 0) {
flags |= unwindstack::MAPS_FLAGS_DEVICE_MAP;
}
maps_.push_back(new MapInfo(start, end, pgoff, flags, name));
});
}
void Maps::Add(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags,
@ -222,26 +89,16 @@ Maps::~Maps() {
}
bool BufferMaps::Parse() {
const char* start_of_line = buffer_;
do {
std::string line;
const char* end_of_line = strchr(start_of_line, '\n');
if (end_of_line == nullptr) {
line = start_of_line;
} else {
line = std::string(start_of_line, end_of_line - start_of_line);
end_of_line++;
}
MapInfo* map_info = InternalParseLine(line.c_str());
if (map_info == nullptr) {
return false;
}
maps_.push_back(map_info);
start_of_line = end_of_line;
} while (start_of_line != nullptr && *start_of_line != '\0');
return true;
std::string content(buffer_);
return android::procinfo::ReadMapFileContent(
&content[0],
[&](uint64_t start, uint64_t end, uint16_t flags, uint64_t pgoff, const char* name) {
// Mark a device map in /dev/ and not in /dev/ashmem/ specially.
if (strncmp(name, "/dev/", 5) == 0 && strncmp(name + 5, "ashmem/", 7) != 0) {
flags |= unwindstack::MAPS_FLAGS_DEVICE_MAP;
}
maps_.push_back(new MapInfo(start, end, pgoff, flags, name));
});
}
const std::string RemoteMaps::GetMapsFile() const {

View file

@ -34,6 +34,13 @@ class Memory;
struct MapInfo {
MapInfo() = default;
MapInfo(uint64_t start, uint64_t end) : start(start), end(end) {}
MapInfo(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags, const char* name)
: start(start),
end(end),
offset(offset),
flags(flags),
name(name),
load_bias(static_cast<uint64_t>(-1)) {}
MapInfo(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags, const std::string& name)
: start(start),
end(end),