procinfo: Read inode number from /proc/<pid>/maps
Adjust all callbacks to include the inode number as well. Fixes: 123532375 Test: libprocinfo_test Test: libdmabufinfo_test Test: libmeminfo_test Change-Id: I71fd75d90d5ee44585011c5ae654a1dd7e185458 Signed-off-by: Sandeep Patil <sspatil@google.com>
This commit is contained in:
parent
c6a2d7d5cd
commit
f31c70989b
8 changed files with 65 additions and 68 deletions
|
@ -46,8 +46,7 @@ BacktraceMap::BacktraceMap(pid_t pid) : pid_(pid) {
|
|||
}
|
||||
}
|
||||
|
||||
BacktraceMap::~BacktraceMap() {
|
||||
}
|
||||
BacktraceMap::~BacktraceMap() {}
|
||||
|
||||
void BacktraceMap::FillIn(uint64_t addr, backtrace_map_t* map) {
|
||||
ScopedBacktraceMapIteratorLock lock(this);
|
||||
|
@ -68,12 +67,13 @@ static bool ParseLine(const char* line, backtrace_map_t* map) {
|
|||
char permissions[5];
|
||||
int name_pos;
|
||||
|
||||
// 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) {
|
||||
// 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) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -90,21 +90,21 @@ static bool ParseLine(const char* line, backtrace_map_t* map) {
|
|||
map->flags |= PROT_EXEC;
|
||||
}
|
||||
|
||||
map->name = line+name_pos;
|
||||
if (!map->name.empty() && map->name[map->name.length()-1] == '\n') {
|
||||
map->name.erase(map->name.length()-1);
|
||||
map->name = line + name_pos;
|
||||
if (!map->name.empty() && map->name[map->name.length() - 1] == '\n') {
|
||||
map->name.erase(map->name.length() - 1);
|
||||
}
|
||||
|
||||
ALOGV("Parsed map: start=%p, end=%p, flags=%x, name=%s",
|
||||
reinterpret_cast<void*>(map->start), reinterpret_cast<void*>(map->end),
|
||||
map->flags, map->name.c_str());
|
||||
ALOGV("Parsed map: start=%p, end=%p, flags=%x, name=%s", reinterpret_cast<void*>(map->start),
|
||||
reinterpret_cast<void*>(map->end), 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];
|
||||
char
|
||||
cmd[sizeof(pid_t) * 3 + sizeof("vmmap -w -resident -submap -allSplitLibs -interleaved ") + 1];
|
||||
char line[1024];
|
||||
// cmd is guaranteed to always be big enough to hold this string.
|
||||
snprintf(cmd, sizeof(cmd), "vmmap -w -resident -submap -allSplitLibs -interleaved %d", pid_);
|
||||
|
@ -113,7 +113,7 @@ bool BacktraceMap::Build() {
|
|||
return false;
|
||||
}
|
||||
|
||||
while(fgets(line, sizeof(line), fp)) {
|
||||
while (fgets(line, sizeof(line), fp)) {
|
||||
backtrace_map_t map;
|
||||
if (ParseLine(line, &map)) {
|
||||
maps_.push_back(map);
|
||||
|
@ -123,7 +123,7 @@ bool BacktraceMap::Build() {
|
|||
return true;
|
||||
#else
|
||||
return android::procinfo::ReadProcessMaps(
|
||||
pid_, [&](uint64_t start, uint64_t end, uint16_t flags, uint64_t, const char* name) {
|
||||
pid_, [&](uint64_t start, uint64_t end, uint16_t flags, uint64_t, ino_t, const char* name) {
|
||||
maps_.resize(maps_.size() + 1);
|
||||
backtrace_map_t& map = maps_.back();
|
||||
map.start = start;
|
||||
|
|
|
@ -123,18 +123,14 @@ static bool ReadDmaBufFdRefs(pid_t pid, std::vector<DmaBuffer>* dmabufs) {
|
|||
auto buf = std::find_if(dmabufs->begin(), dmabufs->end(),
|
||||
[&inode](const DmaBuffer& dbuf) { return dbuf.inode() == inode; });
|
||||
if (buf != dmabufs->end()) {
|
||||
if (buf->name() == "" || buf->name() == "<unknown>")
|
||||
buf->SetName(name);
|
||||
if (buf->exporter() == "" || buf->exporter() == "<unknown>")
|
||||
buf->SetExporter(exporter);
|
||||
if (buf->count() == 0)
|
||||
buf->SetCount(count);
|
||||
if (buf->name() == "" || buf->name() == "<unknown>") buf->SetName(name);
|
||||
if (buf->exporter() == "" || buf->exporter() == "<unknown>") buf->SetExporter(exporter);
|
||||
if (buf->count() == 0) buf->SetCount(count);
|
||||
buf->AddFdRef(pid);
|
||||
return true;
|
||||
}
|
||||
|
||||
DmaBuffer& db =
|
||||
dmabufs->emplace_back(sb.st_ino, sb.st_blocks * 512, count, exporter, name);
|
||||
DmaBuffer& db = dmabufs->emplace_back(sb.st_ino, sb.st_blocks * 512, count, exporter, name);
|
||||
db.AddFdRef(pid);
|
||||
}
|
||||
|
||||
|
@ -155,29 +151,12 @@ static bool ReadDmaBufMapRefs(pid_t pid, std::vector<DmaBuffer>* dmabufs) {
|
|||
// Process the map if it is dmabuf. Add map reference to existing object in 'dmabufs'
|
||||
// if it was already found. If it wasn't create a new one and append it to 'dmabufs'
|
||||
auto account_dmabuf = [&](uint64_t start, uint64_t end, uint16_t /* flags */,
|
||||
uint64_t /* pgoff */, const char* name) {
|
||||
uint64_t /* pgoff */, ino_t inode, const char* name) {
|
||||
// no need to look into this mapping if it is not dmabuf
|
||||
if (!FileIsDmaBuf(std::string(name))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO (b/123532375) : Add inode number to the callback of ReadMapFileContent.
|
||||
//
|
||||
// Workaround: we know 'name' points to the name at the end of 'line'.
|
||||
// We use that to backtrack and pick up the inode number from the line as well.
|
||||
// start end flag pgoff mj:mn inode name
|
||||
// 00400000-00409000 r-xp 00000000 00:00 426998 /dmabuf (deleted)
|
||||
const char* p = name;
|
||||
p--;
|
||||
// skip spaces
|
||||
while (p != line && *p == ' ') {
|
||||
p--;
|
||||
}
|
||||
// walk backwards to the beginning of inode number
|
||||
while (p != line && isdigit(*p)) {
|
||||
p--;
|
||||
}
|
||||
uint64_t inode = strtoull(p, nullptr, 10);
|
||||
auto buf = std::find_if(dmabufs->begin(), dmabufs->end(),
|
||||
[&inode](const DmaBuffer& dbuf) { return dbuf.inode() == inode; });
|
||||
if (buf != dmabufs->end()) {
|
||||
|
|
|
@ -246,7 +246,7 @@ bool ProcMemInfo::ReadMaps(bool get_wss, bool use_pageidle) {
|
|||
// parse and read /proc/<pid>/maps
|
||||
std::string maps_file = ::android::base::StringPrintf("/proc/%d/maps", pid_);
|
||||
if (!::android::procinfo::ReadMapFile(
|
||||
maps_file, [&](uint64_t start, uint64_t end, uint16_t flags, uint64_t pgoff,
|
||||
maps_file, [&](uint64_t start, uint64_t end, uint16_t flags, uint64_t pgoff, ino_t,
|
||||
const char* name) {
|
||||
maps_.emplace_back(Vma(start, end, pgoff, flags, name));
|
||||
})) {
|
||||
|
@ -394,7 +394,7 @@ bool ForEachVmaFromFile(const std::string& path, const VmaCallback& callback) {
|
|||
// If it has, we are looking for the vma stats
|
||||
// 00400000-00409000 r-xp 00000000 fc:00 426998 /usr/lib/gvfs/gvfsd-http
|
||||
if (!::android::procinfo::ReadMapFileContent(
|
||||
line, [&](uint64_t start, uint64_t end, uint16_t flags, uint64_t pgoff,
|
||||
line, [&](uint64_t start, uint64_t end, uint16_t flags, uint64_t pgoff, ino_t,
|
||||
const char* name) {
|
||||
vma.start = start;
|
||||
vma.end = end;
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <android-base/unique_fd.h>
|
||||
|
@ -30,7 +31,8 @@ namespace android {
|
|||
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 {
|
||||
void operator()(uint64_t start, uint64_t end, uint16_t flags, uint64_t, ino_t,
|
||||
const char* name) const {
|
||||
mappings_.emplace_back(start, end, flags & PROT_READ, flags & PROT_WRITE, flags & PROT_EXEC,
|
||||
name);
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ bool ReadMapFileContent(char* content, const CallbackType& callback) {
|
|||
uint64_t end_addr;
|
||||
uint16_t flags;
|
||||
uint64_t pgoff;
|
||||
ino_t inode;
|
||||
char* next_line = content;
|
||||
char* p;
|
||||
|
||||
|
@ -124,18 +125,25 @@ bool ReadMapFileContent(char* content, const CallbackType& callback) {
|
|||
return false;
|
||||
}
|
||||
// inode
|
||||
if (!pass_xdigit() || (*p != '\0' && !pass_space())) {
|
||||
inode = strtoull(p, &end, 10);
|
||||
if (end == p) {
|
||||
return false;
|
||||
}
|
||||
p = end;
|
||||
|
||||
if (*p != '\0' && !pass_space()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// filename
|
||||
callback(start_addr, end_addr, flags, pgoff, p);
|
||||
callback(start_addr, end_addr, flags, pgoff, inode, 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) {
|
||||
inline bool ReadMapFile(const std::string& map_file,
|
||||
const std::function<void(uint64_t, uint64_t, uint16_t, uint64_t, ino_t,
|
||||
const char*)>& callback) {
|
||||
std::string content;
|
||||
if (!android::base::ReadFileToString(map_file, &content)) {
|
||||
return false;
|
||||
|
@ -143,9 +151,9 @@ inline bool ReadMapFile(
|
|||
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) {
|
||||
inline bool ReadProcessMaps(pid_t pid,
|
||||
const std::function<void(uint64_t, uint64_t, uint16_t, uint64_t, ino_t,
|
||||
const char*)>& callback) {
|
||||
return ReadMapFile("/proc/" + std::to_string(pid) + "/maps", callback);
|
||||
}
|
||||
|
||||
|
@ -154,17 +162,18 @@ struct MapInfo {
|
|||
uint64_t end;
|
||||
uint16_t flags;
|
||||
uint64_t pgoff;
|
||||
ino_t inode;
|
||||
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) {}
|
||||
MapInfo(uint64_t start, uint64_t end, uint16_t flags, uint64_t pgoff, ino_t inode,
|
||||
const char* name)
|
||||
: start(start), end(end), flags(flags), pgoff(pgoff), inode(inode), name(name) {}
|
||||
};
|
||||
|
||||
inline bool ReadProcessMaps(pid_t pid, std::vector<MapInfo>* maps) {
|
||||
return ReadProcessMaps(
|
||||
pid, [&](uint64_t start, uint64_t end, uint16_t flags, uint64_t pgoff, const char* name) {
|
||||
maps->emplace_back(start, end, flags, pgoff, name);
|
||||
});
|
||||
pid, [&](uint64_t start, uint64_t end, uint16_t flags, uint64_t pgoff, ino_t inode,
|
||||
const char* name) { maps->emplace_back(start, end, flags, pgoff, inode, name); });
|
||||
}
|
||||
|
||||
} /* namespace procinfo */
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <procinfo/process_map.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
|
@ -31,9 +32,10 @@ static void BM_ReadMapFile(benchmark::State& state) {
|
|||
std::string map_file = android::base::GetExecutableDirectory() + "/testdata/maps";
|
||||
for (auto _ : state) {
|
||||
std::vector<android::procinfo::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); });
|
||||
android::procinfo::ReadMapFile(map_file, [&](uint64_t start, uint64_t end, uint16_t flags,
|
||||
uint64_t pgoff, ino_t inode, const char* name) {
|
||||
maps.emplace_back(start, end, flags, pgoff, inode, name);
|
||||
});
|
||||
CHECK_EQ(maps.size(), 2043u);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,23 +26,27 @@ TEST(process_map, ReadMapFile) {
|
|||
std::string map_file = android::base::GetExecutableDirectory() + "/testdata/maps";
|
||||
std::vector<android::procinfo::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); }));
|
||||
map_file,
|
||||
[&](uint64_t start, uint64_t end, uint16_t flags, uint64_t pgoff, ino_t inode,
|
||||
const char* name) { maps.emplace_back(start, end, flags, pgoff, inode, 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].inode, 10267643UL);
|
||||
ASSERT_EQ(maps[0].name, "[anon:dalvik-main space (region space)]");
|
||||
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].inode, 2407UL);
|
||||
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].inode, 10266154UL);
|
||||
ASSERT_EQ(maps[1260].name,
|
||||
"[anon:dalvik-classes.dex extracted in memory from "
|
||||
"/data/app/com.google.sample.tunnel-HGGRU03Gu1Mwkf_-RnFmvw==/base.apk]");
|
||||
|
@ -51,8 +55,9 @@ TEST(process_map, ReadMapFile) {
|
|||
TEST(process_map, ReadProcessMaps) {
|
||||
std::vector<android::procinfo::MapInfo> maps;
|
||||
ASSERT_TRUE(android::procinfo::ReadProcessMaps(
|
||||
getpid(), [&](uint64_t start, uint64_t end, uint16_t flags, uint64_t pgoff,
|
||||
const char* name) { maps.emplace_back(start, end, flags, pgoff, name); }));
|
||||
getpid(),
|
||||
[&](uint64_t start, uint64_t end, uint16_t flags, uint64_t pgoff, ino_t inode,
|
||||
const char* name) { maps.emplace_back(start, end, flags, pgoff, inode, name); }));
|
||||
ASSERT_GT(maps.size(), 0u);
|
||||
maps.clear();
|
||||
ASSERT_TRUE(android::procinfo::ReadProcessMaps(getpid(), &maps));
|
||||
|
|
|
@ -62,7 +62,7 @@ MapInfo* Maps::Find(uint64_t pc) {
|
|||
bool Maps::Parse() {
|
||||
return android::procinfo::ReadMapFile(
|
||||
GetMapsFile(),
|
||||
[&](uint64_t start, uint64_t end, uint16_t flags, uint64_t pgoff, const char* name) {
|
||||
[&](uint64_t start, uint64_t end, uint16_t flags, uint64_t pgoff, ino_t, 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;
|
||||
|
@ -102,7 +102,7 @@ bool BufferMaps::Parse() {
|
|||
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) {
|
||||
[&](uint64_t start, uint64_t end, uint16_t flags, uint64_t pgoff, ino_t, 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;
|
||||
|
|
Loading…
Reference in a new issue