diff --git a/repos/os/include/util/formatted_output.h b/repos/os/include/util/formatted_output.h index dc4aa7651c..5c5f0af4c5 100644 --- a/repos/os/include/util/formatted_output.h +++ b/repos/os/include/util/formatted_output.h @@ -15,6 +15,7 @@ #define _INCLUDE__OS__UTIL__FORMATTED_OUTPUT_H_ #include +#include namespace Genode { @@ -23,6 +24,8 @@ namespace Genode { template struct Left_aligned; template struct Right_aligned; + class Hex_dump; + /** * Return the number of characters needed when rendering 'args' as text */ @@ -119,4 +122,93 @@ struct Genode::Right_aligned } }; + +class Genode::Hex_dump +{ + private: + + static constexpr size_t _max_bytes_per_line { 16 }; + uint8_t const * const _base; + size_t const _size; + size_t const _num_lines { (_size + _max_bytes_per_line - 1) / _max_bytes_per_line }; + + static bool _printable_ascii(char c) + { + return c > 31 && c < 127; + } + + static void _print_line_as_hex_words(Output &out, uint8_t const *base, size_t size) + { + using Genode::print; + static constexpr size_t max_bytes_per_word { 2 }; + for (size_t idx { 0 }; idx < _max_bytes_per_line; idx++) { + + if (idx && idx % max_bytes_per_word == 0) + print(out, " "); + + if (idx < size) + print(out, Hex(base[idx], Hex::OMIT_PREFIX, Hex::PAD)); + else + print(out, " "); + } + } + + static void _print_line_as_ascii(Output &out, uint8_t const *base, size_t size) + { + using Genode::print; + for (size_t idx { 0 }; idx < size; idx++) { + + char const *char_ptr { (char *)&base[idx] }; + if (_printable_ascii(*char_ptr)) + print(out, Cstring { char_ptr, 1 }); + else + print(out, "."); + } + } + + static void _print_line_offset(Output &out, size_t line_offset) + { + Genode::print(out, Hex((uint32_t)line_offset, Hex::OMIT_PREFIX, Hex::PAD)); + } + + public: + + Hex_dump(auto const &range) + : _base { (uint8_t *)range.start }, _size { range.num_bytes } { } + + void print(Output &out) const + { + using Genode::print; + uint8_t const *prev_line_ptr { nullptr }; + bool prev_line_was_duplicate { false }; + for (size_t line_idx { 0 }; line_idx < _num_lines; line_idx++) { + + size_t const line_offset { line_idx * _max_bytes_per_line }; + size_t const line_size { min((size_t)_max_bytes_per_line, _size - line_offset) }; + uint8_t const *line_ptr { &_base[line_offset] }; + bool const last_line { line_idx == _num_lines - 1 }; + + bool line_is_duplicate { false }; + if (prev_line_ptr) + line_is_duplicate = !memcmp(prev_line_ptr, line_ptr, line_size); + + if (!line_is_duplicate || last_line) { + + _print_line_offset(out, line_offset); + print(out, ": "); + _print_line_as_hex_words(out, line_ptr, line_size); + print(out, " "); + _print_line_as_ascii(out, line_ptr, line_size); + print(out, last_line ? "" : "\n"); + } + if (line_is_duplicate && !prev_line_was_duplicate && !last_line) + print(out, "*\n"); + + + prev_line_ptr = line_ptr; + prev_line_was_duplicate = line_is_duplicate; + } + } +}; + #endif /* _INCLUDE__OS__UTIL__FORMATTED_OUTPUT_H_ */