Skip to content

Commit

Permalink
GTTF: dump registers on crash on 64-bit Linux
Browse files Browse the repository at this point in the history
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
  • Loading branch information
phajdan.jr@chromium.org committed Jan 10, 2013
1 parent f8eee19 commit 22d5b98
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 29 deletions.
6 changes: 5 additions & 1 deletion base/debug/stack_trace.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,11 @@ namespace internal {
// 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
// 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)

} // namespace internal
Expand Down
64 changes: 56 additions & 8 deletions base/debug/stack_trace_posix.cc
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,8 @@ class BacktraceOutputHandler {
void OutputPointer(void* pointer, BacktraceOutputHandler* handler) {
char buf[1024] = { '\0' };
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("]");
}
Expand All @@ -127,7 +128,8 @@ void ProcessBacktrace(void *const *trace,

#if defined(USE_SYMBOLIZE)
for (int i = 0; i < size; ++i) {
handler->HandleOutput("\t");
OutputPointer(trace[i], handler);
handler->HandleOutput(" ");

char buf[1024] = { '\0' };

Expand All @@ -139,7 +141,6 @@ void ProcessBacktrace(void *const *trace,
else
handler->HandleOutput("<unknown>");

OutputPointer(trace[i], handler);
handler->HandleOutput("\n");
}
#else
Expand Down Expand Up @@ -183,13 +184,57 @@ void StackDumpSignalHandler(int signal, siginfo_t* info, ucontext_t* context) {

char buf[1024] = "Received signal ";
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);

debug::StackTrace().PrintBacktrace();

// TODO(shess): Port to Linux.
#if defined(OS_MACOSX)
#if defined(OS_LINUX)
// 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.
#if ARCH_CPU_X86_FAMILY && ARCH_CPU_32_BITS
size_t len;
Expand Down Expand Up @@ -347,7 +392,7 @@ void StackTrace::OutputToStream(std::ostream* os) const {
namespace internal {

// 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.
size_t n = 1;
if (n > sz)
Expand Down Expand Up @@ -387,7 +432,10 @@ char *itoa_r(intptr_t i, char *buf, size_t sz, int base) {
// Output the next digit.
*ptr++ = "0123456789abcdef"[j % base];
j /= base;
} while (j);

if (padding > 0)
padding--;
} while (j > 0 || padding > 0);

// Terminate the output with a NUL character.
*ptr = '\000';
Expand Down
57 changes: 37 additions & 20 deletions base/debug/stack_trace_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -151,59 +151,76 @@ TEST_F(StackTraceTest, AsyncSignalUnsafeSignalHandlerHang) {

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];
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);
return std::string(buffer);
}

} // namespace

TEST_F(StackTraceTest, itoa_r) {
EXPECT_EQ("0", itoa_r_wrapper(0, 128, 10));
EXPECT_EQ("-1", itoa_r_wrapper(-1, 128, 10));
EXPECT_EQ("0", itoa_r_wrapper(0, 128, 10, 0));
EXPECT_EQ("-1", itoa_r_wrapper(-1, 128, 10, 0));

// Test edge cases.
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",
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",
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",
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",
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) {
EXPECT_EQ("ffffffffffffffff", itoa_r_wrapper(-1, 128, 16));
EXPECT_EQ("ffffffffffffffff", itoa_r_wrapper(-1, 128, 16, 0));
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",
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",
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",
itoa_r_wrapper(std::numeric_limits<intptr_t>::max(), 128, 16));
itoa_r_wrapper(std::numeric_limits<intptr_t>::max(), 128, 16, 0));
} else {
ADD_FAILURE() << "Missing test case for your size of intptr_t ("
<< sizeof(intptr_t) << ")";
}

// Test hex output.
EXPECT_EQ("688", itoa_r_wrapper(0x688, 128, 16));
EXPECT_EQ("deadbeef", itoa_r_wrapper(0xdeadbeef, 128, 16));
EXPECT_EQ("688", itoa_r_wrapper(0x688, 128, 16, 0));
EXPECT_EQ("deadbeef", itoa_r_wrapper(0xdeadbeef, 128, 16, 0));

// Check that itoa_r respects passed buffer size limit.
char buffer[1024];
EXPECT_TRUE(internal::itoa_r(0xdeadbeef, buffer, 10, 16));
EXPECT_TRUE(internal::itoa_r(0xdeadbeef, buffer, 9, 16));
EXPECT_FALSE(internal::itoa_r(0xdeadbeef, buffer, 8, 16));
EXPECT_FALSE(internal::itoa_r(0xdeadbeef, buffer, 7, 16));
EXPECT_TRUE(internal::itoa_r(0xdeadbeef, buffer, 10, 16, 0));
EXPECT_TRUE(internal::itoa_r(0xdeadbeef, buffer, 9, 16, 0));
EXPECT_FALSE(internal::itoa_r(0xdeadbeef, buffer, 8, 16, 0));
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)

Expand Down

0 comments on commit 22d5b98

Please sign in to comment.