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_ */