From 43b2e0f9105848da6470458e7c04bf1fd7fcb25c Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 30 Jan 2014 16:58:39 -0800 Subject: Fix multi-line hex dumping and add unit test. Change-Id: I7657018fef5d9c17410a9a634db275555f180014 --- runtime/base/hex_dump.cc | 112 ++++++++++++++++++++++++++++++++++++++++++ runtime/base/hex_dump.h | 55 +++++++++++++++++++++ runtime/base/hex_dump_test.cc | 63 ++++++++++++++++++++++++ runtime/base/logging.cc | 93 ----------------------------------- runtime/base/logging.h | 18 ------- 5 files changed, 230 insertions(+), 111 deletions(-) create mode 100644 runtime/base/hex_dump.cc create mode 100644 runtime/base/hex_dump.h create mode 100644 runtime/base/hex_dump_test.cc (limited to 'runtime/base') diff --git a/runtime/base/hex_dump.cc b/runtime/base/hex_dump.cc new file mode 100644 index 0000000..936c52b --- /dev/null +++ b/runtime/base/hex_dump.cc @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2014 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 "hex_dump.h" + +#include "globals.h" + +#include + +namespace art { + +void HexDump::Dump(std::ostream& os) const { + if (byte_count_ == 0) { + return; + } + + if (address_ == NULL) { + os << "00000000:"; + return; + } + + static const char gHexDigit[] = "0123456789abcdef"; + const unsigned char* addr = reinterpret_cast(address_); + // 01234560: 00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff 0123456789abcdef + char out[(kBitsPerWord / 4) + /* offset */ + 1 + /* colon */ + (16 * 3) + /* 16 hex digits and space */ + 2 + /* white space */ + 16 + /* 16 characters*/ + 1 /* \0 */ ]; + size_t offset; /* offset to show while printing */ + + if (show_actual_addresses_) { + offset = reinterpret_cast(addr); + } else { + offset = 0; + } + memset(out, ' ', sizeof(out)-1); + out[kBitsPerWord / 4] = ':'; + out[sizeof(out)-1] = '\0'; + + size_t byte_count = byte_count_; + size_t gap = offset & 0x0f; + while (byte_count > 0) { + size_t line_offset = offset & ~0x0f; + + char* hex = out; + char* asc = out + (kBitsPerWord / 4) + /* offset */ 1 + /* colon */ + (16 * 3) + /* 16 hex digits and space */ 2 /* white space */; + + for (int i = 0; i < (kBitsPerWord / 4); i++) { + *hex++ = gHexDigit[line_offset >> (kBitsPerWord - 4)]; + line_offset <<= 4; + } + hex++; + hex++; + + size_t count = std::min(byte_count, 16 - gap); + // CHECK_NE(count, 0U); + // CHECK_LE(count + gap, 16U); + + if (gap) { + /* only on first line */ + hex += gap * 3; + asc += gap; + } + + size_t i; + for (i = gap ; i < count + gap; i++) { + *hex++ = gHexDigit[*addr >> 4]; + *hex++ = gHexDigit[*addr & 0x0f]; + hex++; + if (*addr >= 0x20 && *addr < 0x7f /*isprint(*addr)*/) { + *asc++ = *addr; + } else { + *asc++ = '.'; + } + addr++; + } + for (; i < 16; i++) { + /* erase extra stuff; only happens on last line */ + *hex++ = ' '; + *hex++ = ' '; + hex++; + *asc++ = ' '; + } + + os << prefix_ << out; + + gap = 0; + byte_count -= count; + offset += count; + if (byte_count > 0) { + os << "\n"; + } + } +} + +} // namespace art diff --git a/runtime/base/hex_dump.h b/runtime/base/hex_dump.h new file mode 100644 index 0000000..8769ece --- /dev/null +++ b/runtime/base/hex_dump.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2014 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 ART_RUNTIME_BASE_HEX_DUMP_H_ +#define ART_RUNTIME_BASE_HEX_DUMP_H_ + +#include "macros.h" + +#include + +namespace art { + +// Prints a hex dump in this format: +// +// 01234560: 00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff 0123456789abcdef +// 01234568: 00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff 0123456789abcdef +class HexDump { + public: + HexDump(const void* address, size_t byte_count, bool show_actual_addresses, const char* prefix) + : address_(address), byte_count_(byte_count), show_actual_addresses_(show_actual_addresses), + prefix_(prefix) { + } + + void Dump(std::ostream& os) const; + + private: + const void* const address_; + const size_t byte_count_; + const bool show_actual_addresses_; + const char* const prefix_; + + DISALLOW_COPY_AND_ASSIGN(HexDump); +}; + +inline std::ostream& operator<<(std::ostream& os, const HexDump& rhs) { + rhs.Dump(os); + return os; +} + +} // namespace art + +#endif // ART_RUNTIME_BASE_HEX_DUMP_H_ diff --git a/runtime/base/hex_dump_test.cc b/runtime/base/hex_dump_test.cc new file mode 100644 index 0000000..d950961 --- /dev/null +++ b/runtime/base/hex_dump_test.cc @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2014 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 "hex_dump.h" + +#include "globals.h" + +#include "gtest/gtest.h" + +#include + +namespace art { + +TEST(HexDump, OneLine) { + const char* test_text = "0123456789abcdef"; + std::ostringstream oss; + oss << HexDump(test_text, strlen(test_text), false, ""); + EXPECT_STREQ(oss.str().c_str(), + "00000000: 30 31 32 33 34 35 36 37 38 39 61 62 63 64 65 66 0123456789abcdef"); +} + +TEST(HexDump, MultiLine) { + const char* test_text = "0123456789abcdef0123456789ABCDEF"; + std::ostringstream oss; + oss << HexDump(test_text, strlen(test_text), false, ""); + EXPECT_STREQ(oss.str().c_str(), + "00000000: 30 31 32 33 34 35 36 37 38 39 61 62 63 64 65 66 0123456789abcdef\n" + "00000010: 30 31 32 33 34 35 36 37 38 39 41 42 43 44 45 46 0123456789ABCDEF"); +} + +uint64_t g16byte_aligned_number __attribute__ ((aligned(16))); // NOLINT(whitespace/parens) +TEST(HexDump, ShowActualAddresses) { + g16byte_aligned_number = 0x6162636465666768; + std::ostringstream oss; + oss << HexDump(&g16byte_aligned_number, 8, true, ""); + // Compare ignoring pointer. + EXPECT_STREQ(oss.str().c_str() + (kBitsPerWord / 4), + ": 68 67 66 65 64 63 62 61 hgfedcba "); +} + +TEST(HexDump, Prefix) { + const char* test_text = "0123456789abcdef"; + std::ostringstream oss; + oss << HexDump(test_text, strlen(test_text), false, "test prefix: "); + EXPECT_STREQ(oss.str().c_str(), + "test prefix: 00000000: 30 31 32 33 34 35 36 37 38 39 61 62 63 64 65 66 " + "0123456789abcdef"); +} + +} // namespace art diff --git a/runtime/base/logging.cc b/runtime/base/logging.cc index 15554ac..46b8ff2 100644 --- a/runtime/base/logging.cc +++ b/runtime/base/logging.cc @@ -161,97 +161,4 @@ LogMessage::~LogMessage() { } } -HexDump::HexDump(const void* address, size_t byte_count, bool show_actual_addresses) - : address_(address), byte_count_(byte_count), show_actual_addresses_(show_actual_addresses) { -} - -void HexDump::Dump(std::ostream& os) const { - if (byte_count_ == 0) { - return; - } - - if (address_ == NULL) { - os << "00000000:"; - return; - } - - static const char gHexDigit[] = "0123456789abcdef"; - const unsigned char* addr = reinterpret_cast(address_); - // 01234560: 00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff 0123456789abcdef - char out[(kBitsPerWord / 4) + /* offset */ - 1 + /* colon */ - (16 * 3) + /* 16 hex digits and space */ - 2 + /* white space */ - 16 + /* 16 characters*/ - 1 /* \0 */ ]; - size_t offset; /* offset to show while printing */ - - if (show_actual_addresses_) { - offset = reinterpret_cast(addr); - } else { - offset = 0; - } - memset(out, ' ', sizeof(out)-1); - out[kBitsPerWord / 4] = ':'; - out[sizeof(out)-1] = '\0'; - - size_t byte_count = byte_count_; - size_t gap = offset & 0x0f; - while (byte_count) { - size_t line_offset = offset & ~0x0f; - - char* hex = out; - char* asc = out + (kBitsPerWord / 4) + /* offset */ 1 + /* colon */ - (16 * 3) + /* 16 hex digits and space */ 2 /* white space */; - - for (int i = 0; i < (kBitsPerWord / 4); i++) { - *hex++ = gHexDigit[line_offset >> (kBitsPerWord - 4)]; - line_offset <<= 4; - } - hex++; - hex++; - - size_t count = std::min(byte_count, 16 - gap); - CHECK_NE(count, 0U); - CHECK_LE(count + gap, 16U); - - if (gap) { - /* only on first line */ - hex += gap * 3; - asc += gap; - } - - size_t i; - for (i = gap ; i < count + gap; i++) { - *hex++ = gHexDigit[*addr >> 4]; - *hex++ = gHexDigit[*addr & 0x0f]; - hex++; - if (*addr >= 0x20 && *addr < 0x7f /*isprint(*addr)*/) { - *asc++ = *addr; - } else { - *asc++ = '.'; - } - addr++; - } - for (; i < 16; i++) { - /* erase extra stuff; only happens on last line */ - *hex++ = ' '; - *hex++ = ' '; - hex++; - *asc++ = ' '; - } - - os << out; - - gap = 0; - byte_count -= count; - offset += count; - } -} - -std::ostream& operator<<(std::ostream& os, const HexDump& rhs) { - rhs.Dump(os); - return os; -} - } // namespace art diff --git a/runtime/base/logging.h b/runtime/base/logging.h index 8e40da0..075d571 100644 --- a/runtime/base/logging.h +++ b/runtime/base/logging.h @@ -208,24 +208,6 @@ class LogMessage { DISALLOW_COPY_AND_ASSIGN(LogMessage); }; -// Prints a hex dump in this format: -// -// 01234560: 00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff 0123456789abcdef -// 01234568: 00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff 0123456789abcdef -class HexDump { - public: - HexDump(const void* address, size_t byte_count, bool show_actual_addresses = false); - void Dump(std::ostream& os) const; - - private: - const void* address_; - size_t byte_count_; - bool show_actual_addresses_; - - DISALLOW_COPY_AND_ASSIGN(HexDump); -}; -std::ostream& operator<<(std::ostream& os, const HexDump& rhs); - // A convenience to allow any class with a "Dump(std::ostream& os)" member function // but without an operator<< to be used as if it had an operator<<. Use like this: // -- cgit v1.1