Dump memory going from unreadable to readable.
If the first read when dumping memory returns no data, skip ahead to the next page boundary and try and read from there. This fixes a case where the address at which to start dumping memory is unreadable, but crosses back into readable memory. Bug: 22234753 Change-Id: Ie28d5c027013577ca06f5396aba498366a3b6749
This commit is contained in:
parent
41a0654e2a
commit
456abbabf2
3 changed files with 270 additions and 11 deletions
|
@ -60,12 +60,14 @@ class BacktraceMock : public Backtrace {
|
|||
}
|
||||
size_t bytes_available = buffer_.size() - offset;
|
||||
|
||||
if (bytes_partial_read_ > 0) {
|
||||
if (do_partial_read_) {
|
||||
// Do a partial read.
|
||||
if (bytes > bytes_partial_read_) {
|
||||
bytes = bytes_partial_read_;
|
||||
}
|
||||
bytes_partial_read_ -= bytes;
|
||||
// Only support a single partial read.
|
||||
do_partial_read_ = false;
|
||||
} else if (bytes > bytes_available) {
|
||||
bytes = bytes_available;
|
||||
}
|
||||
|
@ -82,6 +84,7 @@ class BacktraceMock : public Backtrace {
|
|||
buffer_.resize(bytes);
|
||||
memcpy(buffer_.data(), buffer, bytes);
|
||||
bytes_partial_read_ = 0;
|
||||
do_partial_read_ = false;
|
||||
last_read_addr_ = 0;
|
||||
}
|
||||
|
||||
|
@ -90,12 +93,14 @@ class BacktraceMock : public Backtrace {
|
|||
abort();
|
||||
}
|
||||
bytes_partial_read_ = bytes;
|
||||
do_partial_read_ = true;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<uint8_t> buffer_;
|
||||
size_t bytes_partial_read_ = 0;
|
||||
uintptr_t last_read_addr_ = 0;
|
||||
bool do_partial_read_ = false;
|
||||
};
|
||||
|
||||
#endif // _DEBUGGERD_TEST_BACKTRACE_MOCK_H
|
||||
|
|
|
@ -502,3 +502,239 @@ TEST_F(DumpMemoryTest, memory_address_nearly_too_high) {
|
|||
ASSERT_STREQ("", getFakeLogBuf().c_str());
|
||||
ASSERT_STREQ("", getFakeLogPrint().c_str());
|
||||
}
|
||||
|
||||
TEST_F(DumpMemoryTest, first_read_empty) {
|
||||
uint8_t buffer[256];
|
||||
for (size_t i = 0; i < sizeof(buffer); i++) {
|
||||
buffer[i] = i;
|
||||
}
|
||||
backtrace_mock_->SetReadData(buffer, sizeof(buffer));
|
||||
backtrace_mock_->SetPartialReadAmount(0);
|
||||
|
||||
size_t page_size = sysconf(_SC_PAGE_SIZE);
|
||||
uintptr_t addr = 0x10000020 + page_size - 120;
|
||||
dump_memory(&log_, backtrace_mock_.get(), addr, "memory near %.2s:", "r4");
|
||||
|
||||
std::string tombstone_contents;
|
||||
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
|
||||
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
|
||||
const char* expected_dump = \
|
||||
"\nmemory near r4:\n"
|
||||
#if defined(__LP64__)
|
||||
" 0000000010000f88 ---------------- ---------------- ................\n"
|
||||
" 0000000010000f98 ---------------- ---------------- ................\n"
|
||||
" 0000000010000fa8 ---------------- ---------------- ................\n"
|
||||
" 0000000010000fb8 ---------------- ---------------- ................\n"
|
||||
" 0000000010000fc8 ---------------- ---------------- ................\n"
|
||||
" 0000000010000fd8 ---------------- ---------------- ................\n"
|
||||
" 0000000010000fe8 ---------------- ---------------- ................\n"
|
||||
" 0000000010000ff8 ---------------- 7f7e7d7c7b7a7978 ........xyz{|}~.\n"
|
||||
" 0000000010001008 8786858483828180 8f8e8d8c8b8a8988 ................\n"
|
||||
" 0000000010001018 9796959493929190 9f9e9d9c9b9a9998 ................\n"
|
||||
" 0000000010001028 a7a6a5a4a3a2a1a0 afaeadacabaaa9a8 ................\n"
|
||||
" 0000000010001038 b7b6b5b4b3b2b1b0 bfbebdbcbbbab9b8 ................\n"
|
||||
" 0000000010001048 c7c6c5c4c3c2c1c0 cfcecdcccbcac9c8 ................\n"
|
||||
" 0000000010001058 d7d6d5d4d3d2d1d0 dfdedddcdbdad9d8 ................\n"
|
||||
" 0000000010001068 e7e6e5e4e3e2e1e0 efeeedecebeae9e8 ................\n"
|
||||
" 0000000010001078 f7f6f5f4f3f2f1f0 fffefdfcfbfaf9f8 ................\n";
|
||||
#else
|
||||
" 10000f88 -------- -------- -------- -------- ................\n"
|
||||
" 10000f98 -------- -------- -------- -------- ................\n"
|
||||
" 10000fa8 -------- -------- -------- -------- ................\n"
|
||||
" 10000fb8 -------- -------- -------- -------- ................\n"
|
||||
" 10000fc8 -------- -------- -------- -------- ................\n"
|
||||
" 10000fd8 -------- -------- -------- -------- ................\n"
|
||||
" 10000fe8 -------- -------- -------- -------- ................\n"
|
||||
" 10000ff8 -------- -------- 7b7a7978 7f7e7d7c ........xyz{|}~.\n"
|
||||
" 10001008 83828180 87868584 8b8a8988 8f8e8d8c ................\n"
|
||||
" 10001018 93929190 97969594 9b9a9998 9f9e9d9c ................\n"
|
||||
" 10001028 a3a2a1a0 a7a6a5a4 abaaa9a8 afaeadac ................\n"
|
||||
" 10001038 b3b2b1b0 b7b6b5b4 bbbab9b8 bfbebdbc ................\n"
|
||||
" 10001048 c3c2c1c0 c7c6c5c4 cbcac9c8 cfcecdcc ................\n"
|
||||
" 10001058 d3d2d1d0 d7d6d5d4 dbdad9d8 dfdedddc ................\n"
|
||||
" 10001068 e3e2e1e0 e7e6e5e4 ebeae9e8 efeeedec ................\n"
|
||||
" 10001078 f3f2f1f0 f7f6f5f4 fbfaf9f8 fffefdfc ................\n";
|
||||
#endif
|
||||
ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
|
||||
|
||||
// Verify that the log buf is empty, and no error messages.
|
||||
ASSERT_STREQ("", getFakeLogBuf().c_str());
|
||||
ASSERT_STREQ("", getFakeLogPrint().c_str());
|
||||
}
|
||||
|
||||
TEST_F(DumpMemoryTest, first_read_empty_second_read_stops) {
|
||||
uint8_t buffer[224];
|
||||
for (size_t i = 0; i < sizeof(buffer); i++) {
|
||||
buffer[i] = i;
|
||||
}
|
||||
backtrace_mock_->SetReadData(buffer, sizeof(buffer));
|
||||
backtrace_mock_->SetPartialReadAmount(0);
|
||||
|
||||
size_t page_size = sysconf(_SC_PAGE_SIZE);
|
||||
uintptr_t addr = 0x10000020 + page_size - 192;
|
||||
dump_memory(&log_, backtrace_mock_.get(), addr, "memory near %.2s:", "r4");
|
||||
|
||||
std::string tombstone_contents;
|
||||
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
|
||||
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
|
||||
const char* expected_dump = \
|
||||
"\nmemory near r4:\n"
|
||||
#if defined(__LP64__)
|
||||
" 0000000010000f40 ---------------- ---------------- ................\n"
|
||||
" 0000000010000f50 ---------------- ---------------- ................\n"
|
||||
" 0000000010000f60 ---------------- ---------------- ................\n"
|
||||
" 0000000010000f70 ---------------- ---------------- ................\n"
|
||||
" 0000000010000f80 ---------------- ---------------- ................\n"
|
||||
" 0000000010000f90 ---------------- ---------------- ................\n"
|
||||
" 0000000010000fa0 ---------------- ---------------- ................\n"
|
||||
" 0000000010000fb0 ---------------- ---------------- ................\n"
|
||||
" 0000000010000fc0 ---------------- ---------------- ................\n"
|
||||
" 0000000010000fd0 ---------------- ---------------- ................\n"
|
||||
" 0000000010000fe0 ---------------- ---------------- ................\n"
|
||||
" 0000000010000ff0 ---------------- ---------------- ................\n"
|
||||
" 0000000010001000 c7c6c5c4c3c2c1c0 cfcecdcccbcac9c8 ................\n"
|
||||
" 0000000010001010 d7d6d5d4d3d2d1d0 dfdedddcdbdad9d8 ................\n"
|
||||
" 0000000010001020 ---------------- ---------------- ................\n"
|
||||
" 0000000010001030 ---------------- ---------------- ................\n";
|
||||
#else
|
||||
" 10000f40 -------- -------- -------- -------- ................\n"
|
||||
" 10000f50 -------- -------- -------- -------- ................\n"
|
||||
" 10000f60 -------- -------- -------- -------- ................\n"
|
||||
" 10000f70 -------- -------- -------- -------- ................\n"
|
||||
" 10000f80 -------- -------- -------- -------- ................\n"
|
||||
" 10000f90 -------- -------- -------- -------- ................\n"
|
||||
" 10000fa0 -------- -------- -------- -------- ................\n"
|
||||
" 10000fb0 -------- -------- -------- -------- ................\n"
|
||||
" 10000fc0 -------- -------- -------- -------- ................\n"
|
||||
" 10000fd0 -------- -------- -------- -------- ................\n"
|
||||
" 10000fe0 -------- -------- -------- -------- ................\n"
|
||||
" 10000ff0 -------- -------- -------- -------- ................\n"
|
||||
" 10001000 c3c2c1c0 c7c6c5c4 cbcac9c8 cfcecdcc ................\n"
|
||||
" 10001010 d3d2d1d0 d7d6d5d4 dbdad9d8 dfdedddc ................\n"
|
||||
" 10001020 -------- -------- -------- -------- ................\n"
|
||||
" 10001030 -------- -------- -------- -------- ................\n";
|
||||
#endif
|
||||
ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
|
||||
|
||||
// Verify that the log buf is empty, and no error messages.
|
||||
ASSERT_STREQ("", getFakeLogBuf().c_str());
|
||||
ASSERT_STREQ("", getFakeLogPrint().c_str());
|
||||
}
|
||||
|
||||
TEST_F(DumpMemoryTest, first_read_empty_next_page_out_of_range) {
|
||||
uint8_t buffer[256];
|
||||
for (size_t i = 0; i < sizeof(buffer); i++) {
|
||||
buffer[i] = i;
|
||||
}
|
||||
backtrace_mock_->SetReadData(buffer, sizeof(buffer));
|
||||
backtrace_mock_->SetPartialReadAmount(0);
|
||||
|
||||
uintptr_t addr = 0x10000020;
|
||||
dump_memory(&log_, backtrace_mock_.get(), addr, "memory near %.2s:", "r4");
|
||||
|
||||
std::string tombstone_contents;
|
||||
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
|
||||
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
|
||||
const char* expected_dump = \
|
||||
"\nmemory near r4:\n"
|
||||
#if defined(__LP64__)
|
||||
" 0000000010000000 ---------------- ---------------- ................\n"
|
||||
" 0000000010000010 ---------------- ---------------- ................\n"
|
||||
" 0000000010000020 ---------------- ---------------- ................\n"
|
||||
" 0000000010000030 ---------------- ---------------- ................\n"
|
||||
" 0000000010000040 ---------------- ---------------- ................\n"
|
||||
" 0000000010000050 ---------------- ---------------- ................\n"
|
||||
" 0000000010000060 ---------------- ---------------- ................\n"
|
||||
" 0000000010000070 ---------------- ---------------- ................\n"
|
||||
" 0000000010000080 ---------------- ---------------- ................\n"
|
||||
" 0000000010000090 ---------------- ---------------- ................\n"
|
||||
" 00000000100000a0 ---------------- ---------------- ................\n"
|
||||
" 00000000100000b0 ---------------- ---------------- ................\n"
|
||||
" 00000000100000c0 ---------------- ---------------- ................\n"
|
||||
" 00000000100000d0 ---------------- ---------------- ................\n"
|
||||
" 00000000100000e0 ---------------- ---------------- ................\n"
|
||||
" 00000000100000f0 ---------------- ---------------- ................\n";
|
||||
#else
|
||||
" 10000000 -------- -------- -------- -------- ................\n"
|
||||
" 10000010 -------- -------- -------- -------- ................\n"
|
||||
" 10000020 -------- -------- -------- -------- ................\n"
|
||||
" 10000030 -------- -------- -------- -------- ................\n"
|
||||
" 10000040 -------- -------- -------- -------- ................\n"
|
||||
" 10000050 -------- -------- -------- -------- ................\n"
|
||||
" 10000060 -------- -------- -------- -------- ................\n"
|
||||
" 10000070 -------- -------- -------- -------- ................\n"
|
||||
" 10000080 -------- -------- -------- -------- ................\n"
|
||||
" 10000090 -------- -------- -------- -------- ................\n"
|
||||
" 100000a0 -------- -------- -------- -------- ................\n"
|
||||
" 100000b0 -------- -------- -------- -------- ................\n"
|
||||
" 100000c0 -------- -------- -------- -------- ................\n"
|
||||
" 100000d0 -------- -------- -------- -------- ................\n"
|
||||
" 100000e0 -------- -------- -------- -------- ................\n"
|
||||
" 100000f0 -------- -------- -------- -------- ................\n";
|
||||
#endif
|
||||
ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
|
||||
|
||||
// Verify that the log buf is empty, and no error messages.
|
||||
ASSERT_STREQ("", getFakeLogBuf().c_str());
|
||||
ASSERT_STREQ("", getFakeLogPrint().c_str());
|
||||
}
|
||||
|
||||
TEST_F(DumpMemoryTest, first_read_empty_next_page_out_of_range_fence_post) {
|
||||
uint8_t buffer[256];
|
||||
for (size_t i = 0; i < sizeof(buffer); i++) {
|
||||
buffer[i] = i;
|
||||
}
|
||||
backtrace_mock_->SetReadData(buffer, sizeof(buffer));
|
||||
backtrace_mock_->SetPartialReadAmount(0);
|
||||
|
||||
size_t page_size = sysconf(_SC_PAGE_SIZE);
|
||||
uintptr_t addr = 0x10000020 + page_size - 256;
|
||||
|
||||
dump_memory(&log_, backtrace_mock_.get(), addr, "memory near %.2s:", "r4");
|
||||
|
||||
std::string tombstone_contents;
|
||||
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
|
||||
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
|
||||
const char* expected_dump = \
|
||||
"\nmemory near r4:\n"
|
||||
#if defined(__LP64__)
|
||||
" 0000000010000f00 ---------------- ---------------- ................\n"
|
||||
" 0000000010000f10 ---------------- ---------------- ................\n"
|
||||
" 0000000010000f20 ---------------- ---------------- ................\n"
|
||||
" 0000000010000f30 ---------------- ---------------- ................\n"
|
||||
" 0000000010000f40 ---------------- ---------------- ................\n"
|
||||
" 0000000010000f50 ---------------- ---------------- ................\n"
|
||||
" 0000000010000f60 ---------------- ---------------- ................\n"
|
||||
" 0000000010000f70 ---------------- ---------------- ................\n"
|
||||
" 0000000010000f80 ---------------- ---------------- ................\n"
|
||||
" 0000000010000f90 ---------------- ---------------- ................\n"
|
||||
" 0000000010000fa0 ---------------- ---------------- ................\n"
|
||||
" 0000000010000fb0 ---------------- ---------------- ................\n"
|
||||
" 0000000010000fc0 ---------------- ---------------- ................\n"
|
||||
" 0000000010000fd0 ---------------- ---------------- ................\n"
|
||||
" 0000000010000fe0 ---------------- ---------------- ................\n"
|
||||
" 0000000010000ff0 ---------------- ---------------- ................\n";
|
||||
#else
|
||||
" 10000f00 -------- -------- -------- -------- ................\n"
|
||||
" 10000f10 -------- -------- -------- -------- ................\n"
|
||||
" 10000f20 -------- -------- -------- -------- ................\n"
|
||||
" 10000f30 -------- -------- -------- -------- ................\n"
|
||||
" 10000f40 -------- -------- -------- -------- ................\n"
|
||||
" 10000f50 -------- -------- -------- -------- ................\n"
|
||||
" 10000f60 -------- -------- -------- -------- ................\n"
|
||||
" 10000f70 -------- -------- -------- -------- ................\n"
|
||||
" 10000f80 -------- -------- -------- -------- ................\n"
|
||||
" 10000f90 -------- -------- -------- -------- ................\n"
|
||||
" 10000fa0 -------- -------- -------- -------- ................\n"
|
||||
" 10000fb0 -------- -------- -------- -------- ................\n"
|
||||
" 10000fc0 -------- -------- -------- -------- ................\n"
|
||||
" 10000fd0 -------- -------- -------- -------- ................\n"
|
||||
" 10000fe0 -------- -------- -------- -------- ................\n"
|
||||
" 10000ff0 -------- -------- -------- -------- ................\n";
|
||||
#endif
|
||||
ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
|
||||
|
||||
// Verify that the log buf is empty, and no error messages.
|
||||
ASSERT_STREQ("", getFakeLogBuf().c_str());
|
||||
ASSERT_STREQ("", getFakeLogPrint().c_str());
|
||||
}
|
||||
|
|
|
@ -156,13 +156,28 @@ void dump_memory(log_t* log, Backtrace* backtrace, uintptr_t addr, const char* f
|
|||
bytes &= ~(sizeof(uintptr_t) - 1);
|
||||
}
|
||||
|
||||
if (bytes < MEMORY_BYTES_TO_DUMP && bytes > 0) {
|
||||
// Try to do one more read. This could happen if a read crosses a map, but
|
||||
// the maps do not have any break between them. Only requires one extra
|
||||
// read because a map has to contain at least one page, and the total
|
||||
// number of bytes to dump is smaller than a page.
|
||||
size_t bytes2 = backtrace->Read(addr + bytes, reinterpret_cast<uint8_t*>(data) + bytes,
|
||||
sizeof(data) - bytes);
|
||||
uintptr_t start = 0;
|
||||
bool skip_2nd_read = false;
|
||||
if (bytes == 0) {
|
||||
// In this case, we might want to try another read at the beginning of
|
||||
// the next page only if it's within the amount of memory we would have
|
||||
// read.
|
||||
size_t page_size = sysconf(_SC_PAGE_SIZE);
|
||||
start = ((addr + (page_size - 1)) & ~(page_size - 1)) - addr;
|
||||
if (start == 0 || start >= MEMORY_BYTES_TO_DUMP) {
|
||||
skip_2nd_read = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (bytes < MEMORY_BYTES_TO_DUMP && !skip_2nd_read) {
|
||||
// Try to do one more read. This could happen if a read crosses a map,
|
||||
// but the maps do not have any break between them. Or it could happen
|
||||
// if reading from an unreadable map, but the read would cross back
|
||||
// into a readable map. Only requires one extra read because a map has
|
||||
// to contain at least one page, and the total number of bytes to dump
|
||||
// is smaller than a page.
|
||||
size_t bytes2 = backtrace->Read(addr + start + bytes, reinterpret_cast<uint8_t*>(data) + bytes,
|
||||
sizeof(data) - bytes - start);
|
||||
bytes += bytes2;
|
||||
if (bytes2 > 0 && bytes % sizeof(uintptr_t) != 0) {
|
||||
// This should never happen, but we'll try and continue any way.
|
||||
|
@ -178,15 +193,16 @@ void dump_memory(log_t* log, Backtrace* backtrace, uintptr_t addr, const char* f
|
|||
// On 32-bit machines, there are still 16 bytes per line but addresses and
|
||||
// words are of course presented differently.
|
||||
uintptr_t* data_ptr = data;
|
||||
size_t current = 0;
|
||||
size_t total_bytes = start + bytes;
|
||||
for (size_t line = 0; line < MEMORY_BYTES_TO_DUMP / MEMORY_BYTES_PER_LINE; line++) {
|
||||
std::string logline;
|
||||
android::base::StringAppendF(&logline, " %" PRIPTR, addr);
|
||||
|
||||
addr += MEMORY_BYTES_PER_LINE;
|
||||
std::string ascii;
|
||||
for (size_t i = 0; i < MEMORY_BYTES_PER_LINE / sizeof(uintptr_t); i++, data_ptr++) {
|
||||
if (bytes >= sizeof(uintptr_t)) {
|
||||
bytes -= sizeof(uintptr_t);
|
||||
for (size_t i = 0; i < MEMORY_BYTES_PER_LINE / sizeof(uintptr_t); i++) {
|
||||
if (current >= start && current + sizeof(uintptr_t) <= total_bytes) {
|
||||
android::base::StringAppendF(&logline, " %" PRIPTR, *data_ptr);
|
||||
|
||||
// Fill out the ascii string from the data.
|
||||
|
@ -198,10 +214,12 @@ void dump_memory(log_t* log, Backtrace* backtrace, uintptr_t addr, const char* f
|
|||
ascii += '.';
|
||||
}
|
||||
}
|
||||
data_ptr++;
|
||||
} else {
|
||||
logline += ' ' + std::string(sizeof(uintptr_t) * 2, '-');
|
||||
ascii += std::string(sizeof(uintptr_t), '.');
|
||||
}
|
||||
current += sizeof(uintptr_t);
|
||||
}
|
||||
_LOG(log, logtype::MEMORY, "%s %s\n", logline.c_str(), ascii.c_str());
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue