GTTF: dump registers on crash on 64-bit Linux

BUG=none

Review URL: https://codereview.chromium.org/11745003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@176110 0039d316-1c4b-4281-b951-d872f2087c98
parent f8eee19d
...@@ -86,7 +86,11 @@ namespace internal { ...@@ -86,7 +86,11 @@ namespace internal {
// conversion was successful or NULL otherwise. It never writes more than "sz" // conversion was successful or NULL otherwise. It never writes more than "sz"
// bytes. Output will be truncated as needed, and a NUL character is always // bytes. Output will be truncated as needed, and a NUL character is always
// appended. // appended.
BASE_EXPORT char *itoa_r(intptr_t i, char *buf, size_t sz, int base); BASE_EXPORT char *itoa_r(intptr_t i,
char *buf,
size_t sz,
int base,
size_t padding);
#endif // defined(OS_POSIX) && !defined(OS_ANDROID) #endif // defined(OS_POSIX) && !defined(OS_ANDROID)
} // namespace internal } // namespace internal
......
...@@ -114,7 +114,8 @@ class BacktraceOutputHandler { ...@@ -114,7 +114,8 @@ class BacktraceOutputHandler {
void OutputPointer(void* pointer, BacktraceOutputHandler* handler) { void OutputPointer(void* pointer, BacktraceOutputHandler* handler) {
char buf[1024] = { '\0' }; char buf[1024] = { '\0' };
handler->HandleOutput(" [0x"); handler->HandleOutput(" [0x");
internal::itoa_r(reinterpret_cast<intptr_t>(pointer), buf, sizeof(buf), 16); internal::itoa_r(reinterpret_cast<intptr_t>(pointer),
buf, sizeof(buf), 16, 12);
handler->HandleOutput(buf); handler->HandleOutput(buf);
handler->HandleOutput("]"); handler->HandleOutput("]");
} }
...@@ -127,7 +128,8 @@ void ProcessBacktrace(void *const *trace, ...@@ -127,7 +128,8 @@ void ProcessBacktrace(void *const *trace,
#if defined(USE_SYMBOLIZE) #if defined(USE_SYMBOLIZE)
for (int i = 0; i < size; ++i) { for (int i = 0; i < size; ++i) {
handler->HandleOutput("\t"); OutputPointer(trace[i], handler);
handler->HandleOutput(" ");
char buf[1024] = { '\0' }; char buf[1024] = { '\0' };
...@@ -139,7 +141,6 @@ void ProcessBacktrace(void *const *trace, ...@@ -139,7 +141,6 @@ void ProcessBacktrace(void *const *trace,
else else
handler->HandleOutput("<unknown>"); handler->HandleOutput("<unknown>");
OutputPointer(trace[i], handler);
handler->HandleOutput("\n"); handler->HandleOutput("\n");
} }
#else #else
...@@ -183,13 +184,57 @@ void StackDumpSignalHandler(int signal, siginfo_t* info, ucontext_t* context) { ...@@ -183,13 +184,57 @@ void StackDumpSignalHandler(int signal, siginfo_t* info, ucontext_t* context) {
char buf[1024] = "Received signal "; char buf[1024] = "Received signal ";
size_t buf_len = strlen(buf); size_t buf_len = strlen(buf);
internal::itoa_r(signal, buf + buf_len, sizeof(buf) - buf_len, 10); internal::itoa_r(signal, buf + buf_len, sizeof(buf) - buf_len, 10, 0);
RAW_LOG(ERROR, buf); RAW_LOG(ERROR, buf);
debug::StackTrace().PrintBacktrace(); debug::StackTrace().PrintBacktrace();
// TODO(shess): Port to Linux. #if defined(OS_LINUX)
#if defined(OS_MACOSX) // TODO(phajdan.jr): Port to 32-bit.
#if ARCH_CPU_X86_FAMILY && ARCH_CPU_64_BITS
const struct {
const char* label;
greg_t value;
} registers[] = {
{ " r8: ", context->uc_mcontext.gregs[REG_R8] },
{ " r9: ", context->uc_mcontext.gregs[REG_R9] },
{ " r10: ", context->uc_mcontext.gregs[REG_R10] },
{ " r11: ", context->uc_mcontext.gregs[REG_R11] },
{ " r12: ", context->uc_mcontext.gregs[REG_R12] },
{ " r13: ", context->uc_mcontext.gregs[REG_R13] },
{ " r14: ", context->uc_mcontext.gregs[REG_R14] },
{ " r15: ", context->uc_mcontext.gregs[REG_R15] },
{ " di: ", context->uc_mcontext.gregs[REG_RDI] },
{ " si: ", context->uc_mcontext.gregs[REG_RSI] },
{ " bp: ", context->uc_mcontext.gregs[REG_RBP] },
{ " bx: ", context->uc_mcontext.gregs[REG_RBX] },
{ " dx: ", context->uc_mcontext.gregs[REG_RDX] },
{ " ax: ", context->uc_mcontext.gregs[REG_RAX] },
{ " cx: ", context->uc_mcontext.gregs[REG_RCX] },
{ " sp: ", context->uc_mcontext.gregs[REG_RSP] },
{ " ip: ", context->uc_mcontext.gregs[REG_RIP] },
{ " efl: ", context->uc_mcontext.gregs[REG_EFL] },
{ " cgf: ", context->uc_mcontext.gregs[REG_CSGSFS] },
{ " erf: ", context->uc_mcontext.gregs[REG_ERR] },
{ " trp: ", context->uc_mcontext.gregs[REG_TRAPNO] },
{ " msk: ", context->uc_mcontext.gregs[REG_OLDMASK] },
{ " cr2: ", context->uc_mcontext.gregs[REG_CR2] },
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(registers); i++) {
HANDLE_EINTR(write(STDERR_FILENO,
registers[i].label,
strlen(registers[i].label)));
internal::itoa_r(registers[i].value, buf, sizeof(buf), 16, 16);
HANDLE_EINTR(write(STDERR_FILENO, buf, strlen(buf)));
if ((i + 1) % 4 == 0) {
HANDLE_EINTR(write(STDERR_FILENO, "\n", 1));
}
}
HANDLE_EINTR(write(STDERR_FILENO, "\n", 1));
#endif
#elif defined(OS_MACOSX)
// TODO(shess): Port to 64-bit. // TODO(shess): Port to 64-bit.
#if ARCH_CPU_X86_FAMILY && ARCH_CPU_32_BITS #if ARCH_CPU_X86_FAMILY && ARCH_CPU_32_BITS
size_t len; size_t len;
...@@ -347,7 +392,7 @@ void StackTrace::OutputToStream(std::ostream* os) const { ...@@ -347,7 +392,7 @@ void StackTrace::OutputToStream(std::ostream* os) const {
namespace internal { namespace internal {
// NOTE: code from sandbox/linux/seccomp-bpf/demo.cc. // NOTE: code from sandbox/linux/seccomp-bpf/demo.cc.
char *itoa_r(intptr_t i, char *buf, size_t sz, int base) { char *itoa_r(intptr_t i, char *buf, size_t sz, int base, size_t padding) {
// Make sure we can write at least one NUL byte. // Make sure we can write at least one NUL byte.
size_t n = 1; size_t n = 1;
if (n > sz) if (n > sz)
...@@ -387,7 +432,10 @@ char *itoa_r(intptr_t i, char *buf, size_t sz, int base) { ...@@ -387,7 +432,10 @@ char *itoa_r(intptr_t i, char *buf, size_t sz, int base) {
// Output the next digit. // Output the next digit.
*ptr++ = "0123456789abcdef"[j % base]; *ptr++ = "0123456789abcdef"[j % base];
j /= base; j /= base;
} while (j);
if (padding > 0)
padding--;
} while (j > 0 || padding > 0);
// Terminate the output with a NUL character. // Terminate the output with a NUL character.
*ptr = '\000'; *ptr = '\000';
......
...@@ -151,11 +151,11 @@ TEST_F(StackTraceTest, AsyncSignalUnsafeSignalHandlerHang) { ...@@ -151,11 +151,11 @@ TEST_F(StackTraceTest, AsyncSignalUnsafeSignalHandlerHang) {
namespace { namespace {
std::string itoa_r_wrapper(intptr_t i, size_t sz, int base) { std::string itoa_r_wrapper(intptr_t i, size_t sz, int base, size_t padding) {
char buffer[1024]; char buffer[1024];
CHECK_LE(sz, sizeof(buffer)); CHECK_LE(sz, sizeof(buffer));
char* result = internal::itoa_r(i, buffer, sz, base); char* result = internal::itoa_r(i, buffer, sz, base, padding);
EXPECT_TRUE(result); EXPECT_TRUE(result);
return std::string(buffer); return std::string(buffer);
} }
...@@ -163,47 +163,64 @@ std::string itoa_r_wrapper(intptr_t i, size_t sz, int base) { ...@@ -163,47 +163,64 @@ std::string itoa_r_wrapper(intptr_t i, size_t sz, int base) {
} // namespace } // namespace
TEST_F(StackTraceTest, itoa_r) { TEST_F(StackTraceTest, itoa_r) {
EXPECT_EQ("0", itoa_r_wrapper(0, 128, 10)); EXPECT_EQ("0", itoa_r_wrapper(0, 128, 10, 0));
EXPECT_EQ("-1", itoa_r_wrapper(-1, 128, 10)); EXPECT_EQ("-1", itoa_r_wrapper(-1, 128, 10, 0));
// Test edge cases. // Test edge cases.
if (sizeof(intptr_t) == 4) { if (sizeof(intptr_t) == 4) {
EXPECT_EQ("ffffffff", itoa_r_wrapper(-1, 128, 16)); EXPECT_EQ("ffffffff", itoa_r_wrapper(-1, 128, 16, 0));
EXPECT_EQ("-2147483648", EXPECT_EQ("-2147483648",
itoa_r_wrapper(std::numeric_limits<intptr_t>::min(), 128, 10)); itoa_r_wrapper(std::numeric_limits<intptr_t>::min(), 128, 10, 0));
EXPECT_EQ("2147483647", EXPECT_EQ("2147483647",
itoa_r_wrapper(std::numeric_limits<intptr_t>::max(), 128, 10)); itoa_r_wrapper(std::numeric_limits<intptr_t>::max(), 128, 10, 0));
EXPECT_EQ("80000000", EXPECT_EQ("80000000",
itoa_r_wrapper(std::numeric_limits<intptr_t>::min(), 128, 16)); itoa_r_wrapper(std::numeric_limits<intptr_t>::min(), 128, 16, 0));
EXPECT_EQ("7fffffff", EXPECT_EQ("7fffffff",
itoa_r_wrapper(std::numeric_limits<intptr_t>::max(), 128, 16)); itoa_r_wrapper(std::numeric_limits<intptr_t>::max(), 128, 16, 0));
} else if (sizeof(intptr_t) == 8) { } else if (sizeof(intptr_t) == 8) {
EXPECT_EQ("ffffffffffffffff", itoa_r_wrapper(-1, 128, 16)); EXPECT_EQ("ffffffffffffffff", itoa_r_wrapper(-1, 128, 16, 0));
EXPECT_EQ("-9223372036854775808", EXPECT_EQ("-9223372036854775808",
itoa_r_wrapper(std::numeric_limits<intptr_t>::min(), 128, 10)); itoa_r_wrapper(std::numeric_limits<intptr_t>::min(), 128, 10, 0));
EXPECT_EQ("9223372036854775807", EXPECT_EQ("9223372036854775807",
itoa_r_wrapper(std::numeric_limits<intptr_t>::max(), 128, 10)); itoa_r_wrapper(std::numeric_limits<intptr_t>::max(), 128, 10, 0));
EXPECT_EQ("8000000000000000", EXPECT_EQ("8000000000000000",
itoa_r_wrapper(std::numeric_limits<intptr_t>::min(), 128, 16)); itoa_r_wrapper(std::numeric_limits<intptr_t>::min(), 128, 16, 0));
EXPECT_EQ("7fffffffffffffff", EXPECT_EQ("7fffffffffffffff",
itoa_r_wrapper(std::numeric_limits<intptr_t>::max(), 128, 16)); itoa_r_wrapper(std::numeric_limits<intptr_t>::max(), 128, 16, 0));
} else { } else {
ADD_FAILURE() << "Missing test case for your size of intptr_t (" ADD_FAILURE() << "Missing test case for your size of intptr_t ("
<< sizeof(intptr_t) << ")"; << sizeof(intptr_t) << ")";
} }
// Test hex output. // Test hex output.
EXPECT_EQ("688", itoa_r_wrapper(0x688, 128, 16)); EXPECT_EQ("688", itoa_r_wrapper(0x688, 128, 16, 0));
EXPECT_EQ("deadbeef", itoa_r_wrapper(0xdeadbeef, 128, 16)); EXPECT_EQ("deadbeef", itoa_r_wrapper(0xdeadbeef, 128, 16, 0));
// Check that itoa_r respects passed buffer size limit. // Check that itoa_r respects passed buffer size limit.
char buffer[1024]; char buffer[1024];
EXPECT_TRUE(internal::itoa_r(0xdeadbeef, buffer, 10, 16)); EXPECT_TRUE(internal::itoa_r(0xdeadbeef, buffer, 10, 16, 0));
EXPECT_TRUE(internal::itoa_r(0xdeadbeef, buffer, 9, 16)); EXPECT_TRUE(internal::itoa_r(0xdeadbeef, buffer, 9, 16, 0));
EXPECT_FALSE(internal::itoa_r(0xdeadbeef, buffer, 8, 16)); EXPECT_FALSE(internal::itoa_r(0xdeadbeef, buffer, 8, 16, 0));
EXPECT_FALSE(internal::itoa_r(0xdeadbeef, buffer, 7, 16)); EXPECT_FALSE(internal::itoa_r(0xdeadbeef, buffer, 7, 16, 0));
EXPECT_TRUE(internal::itoa_r(0xbeef, buffer, 5, 16, 4));
EXPECT_FALSE(internal::itoa_r(0xbeef, buffer, 5, 16, 5));
EXPECT_FALSE(internal::itoa_r(0xbeef, buffer, 5, 16, 6));
// Test padding.
EXPECT_EQ("1", itoa_r_wrapper(1, 128, 10, 0));
EXPECT_EQ("1", itoa_r_wrapper(1, 128, 10, 1));
EXPECT_EQ("01", itoa_r_wrapper(1, 128, 10, 2));
EXPECT_EQ("001", itoa_r_wrapper(1, 128, 10, 3));
EXPECT_EQ("0001", itoa_r_wrapper(1, 128, 10, 4));
EXPECT_EQ("00001", itoa_r_wrapper(1, 128, 10, 5));
EXPECT_EQ("688", itoa_r_wrapper(0x688, 128, 16, 0));
EXPECT_EQ("688", itoa_r_wrapper(0x688, 128, 16, 1));
EXPECT_EQ("688", itoa_r_wrapper(0x688, 128, 16, 2));
EXPECT_EQ("688", itoa_r_wrapper(0x688, 128, 16, 3));
EXPECT_EQ("0688", itoa_r_wrapper(0x688, 128, 16, 4));
EXPECT_EQ("00688", itoa_r_wrapper(0x688, 128, 16, 5));
} }
#endif // defined(OS_POSIX) && !defined(OS_ANDROID) #endif // defined(OS_POSIX) && !defined(OS_ANDROID)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment