Loading [MathJax]/extensions/tex2jax.js
Hermes
All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
memory_dump.h
Go to the documentation of this file.
1
31
32#ifndef HERMES_LOG_MEMORY_DUMP_H
33#define HERMES_LOG_MEMORY_DUMP_H
34
35#include <hermes/common/debug.h>
36#include <hermes/common/defs.h>
37#include <hermes/common/str.h>
41#include <iostream>
42#include <iomanip>
43#include <cstdlib> // system
44
45namespace hermes {
46
50 none = 0x0,
51 binary = 0x1,
52 decimal = 0x2,
53 hexadecimal = 0x4,
54 hexii = 0x8,
55 hide_header = 0x10,
56 cache_align = 0x20,
57 hide_zeros = 0x40,
58 show_ascii = 0x80,
59 save_to_string = 0x100,
60 write_to_console = 0x200,
61 colored_output = 0x400,
62 type_values = 0x800
63};
66
67// *********************************************************************************************************************
68// MemoryDumper
69// *********************************************************************************************************************
72public:
97 struct RegionLayout {
99 RegionLayout() = default;
105 return *this;
106 }
110 RegionLayout &withColor(const std::string &console_color) {
112 return *this;
113 }
119 return *this;
120 }
125 type = t;
126 return *this;
127 }
133 std::size_t new_offset = 0;
134 if (!sub_regions.empty())
135 new_offset = sub_regions.back().offset + sub_regions.back().field_size_in_bytes * sub_regions.back().count;
136 sub_regions.push_back(sub_region);
137 sub_regions.back().offset = new_offset;
139 field_size_in_bytes += sub_region.field_size_in_bytes * sub_region.count;
140 return *this;
141 }
146 std::size_t new_offset = 0;
147 if (!sub_regions.empty())
148 new_offset = sub_regions.back().offset + sub_regions.back().field_size_in_bytes * sub_regions.back().count;
149 sub_regions.push_back(sub_region);
150 sub_regions.back().offset = new_offset;
152 field_size_in_bytes += sub_region.field_size_in_bytes * sub_region.count;
153 }
157 template<typename T>
159 type = DataTypes::typeFrom<T>();
160 return *this;
161 }
166 template<typename T>
169 field_size_in_bytes = sizeof(T);
170 return *this;
171 }
176 RegionLayout &withSize(std::size_t size_in_bytes, std::size_t element_count = 1) {
179 return *this;
180 }
183 [[nodiscard]] std::size_t sizeInBytes() const { return field_size_in_bytes * count; }
189 for (auto &s : sub_regions)
190 field_size_in_bytes += s.field_size_in_bytes * s.count;
191 }
193 void clear() {
194 *this = RegionLayout();
195 }
196
197 std::size_t offset{0};
198 std::size_t field_size_in_bytes{0};
199 std::size_t count{1};
201 std::vector<RegionLayout> sub_regions{};
202 DataType type{DataType::CUSTOM};
203 };
204
205 // *******************************************************************************************************************
206 // STATIC METHODS
207 // *******************************************************************************************************************
213 template<typename T>
214 static std::string dumpInfo(const T *data, std::size_t size) {
215 auto alignment = alignof(T);
216 auto ptr = reinterpret_cast<const u8 * >(data);
217 ptrdiff_t down_shift = reinterpret_cast<uintptr_t >(ptr) & (64 - 1);
218 uintptr_t aligned_base_address = reinterpret_cast<uintptr_t >(ptr) - down_shift;
219 auto size_in_bytes = sizeof(T) * size + down_shift;
220 Str s = "Memory Block Information\n";
221 s.appendLine(" Address:\t", Str::addressOf(reinterpret_cast<uintptr_t>(data)));
222 s.appendLine(" Block Size:\t", sizeof(T) * size, " bytes");
223 s.appendLine(" Left Alignment");
224 s.appendLine(" Type Alignment:\t", alignment);
225 s.appendLine(" Shift:\t", down_shift);
226 s.appendLine(" Address:\t", Str::addressOf(reinterpret_cast<uintptr_t>(aligned_base_address)));
227 s.appendLine(" Total Block Size:\t", size_in_bytes, " bytes");
228 return s.str();
229 }
238 template<typename T>
239 static std::string dump(const T *data, std::size_t size, u32 bytes_per_row = 8,
241 memory_dumper_options options = memory_dumper_options::none) {
242 // check options_
243 auto hide_zeros = HERMES_MASK_BIT(options, memory_dumper_options::hide_zeros);
244 auto include_header = !HERMES_MASK_BIT(options, memory_dumper_options::hide_header);
245 auto align_data = HERMES_MASK_BIT(options, memory_dumper_options::cache_align);
246 auto show_ascii = HERMES_MASK_BIT(options, memory_dumper_options::show_ascii);
247 auto write_to_console = HERMES_MASK_BIT(options, memory_dumper_options::write_to_console);
248 auto save_string = HERMES_MASK_BIT(options, memory_dumper_options::save_to_string);
249 auto colored_output = HERMES_MASK_BIT(options, memory_dumper_options::colored_output);
250 auto show_type_values = HERMES_MASK_BIT(options, memory_dumper_options::type_values);
252 write_to_console = true;
253 // output string
255 // address size
257 // compute column size for text alignment
259 if (HERMES_MASK_BIT(options, memory_dumper_options::decimal))
261 else if (HERMES_MASK_BIT(options, memory_dumper_options::binary))
265 u8 address_column_size = address_digit_count + 2 + 2; // 0x + \t
266 if (include_header) {
267 Str s = std::string(address_column_size, ' ');
268 for (u32 i = 0; i < bytes_per_row; ++i) {
269 auto bs = Str::binaryToHex(i, true, true);
270 if (i % 8 == 0)
271 s.append(" ");
272 s.append(std::setw(column_size), !bs.empty() ? bs : "0", " ");
273 }
274 if (save_string)
275 output_string += s;
277 std::cout << s;
278 }
279 auto alignment = (align_data) ? 64 : 1;
280 auto ptr = reinterpret_cast<const u8 * >(data);
281 ptrdiff_t shift = reinterpret_cast<uintptr_t >(ptr) & (alignment - 1);
282 uintptr_t aligned_base_address = reinterpret_cast<uintptr_t >(ptr) - shift;
284 ptrdiff_t size_in_bytes = sizeof(T) * size + shift;
285 auto line_count = 0;
286 while (byte_offset < size_in_bytes) {
287 { // ADDRESS
288 Str s;
289 s.appendLine();
290 s.append(Str::addressOf(reinterpret_cast<uintptr_t >((void *) (aligned_base_address + byte_offset))).c_str(),
291 " ");
292 if (save_string)
293 output_string += s;
294 if (write_to_console) {
295 if (colored_output && line_count % 2)
297 else
298 std::cout << s;
299 }
300 line_count++;
301 }
302 std::string ascii_data;
303 std::string type_values;
304 for (ptrdiff_t i = 0; i < bytes_per_row; i++, byte_offset++) {
305 if (i % 8 == 0) {
307 std::cout << " ";
308 if (save_string)
309 output_string.append(" ");
310 }
311 if (aligned_base_address + byte_offset < reinterpret_cast<uintptr_t >(ptr) || byte_offset >= size_in_bytes) {
313 std::cout << std::string(column_size, ' ') + " ";
314 if (save_string)
315 output_string += std::string(column_size, ' ') + " ";
316 ascii_data += '.';
317 continue;
318 }
319 u8 byte = *(reinterpret_cast<u8 *>(aligned_base_address + byte_offset));
320 Str s;
321 if (!hide_zeros || byte) {
322 if (HERMES_MASK_BIT(options, memory_dumper_options::hexadecimal))
323 s.append(Str::binaryToHex(byte), " ");
324 else if (HERMES_MASK_BIT(options, memory_dumper_options::decimal))
325 s.append(std::setfill('0'), std::setw(column_size), static_cast<u32>(byte), ' ');
326 else if (HERMES_MASK_BIT(options, memory_dumper_options::binary))
327 s.append(Str::byteToBinary(byte), " ");
328 else if (HERMES_MASK_BIT(options, memory_dumper_options::hexii))
329 s.append(std::string(column_size, ' '), " ");
330 else
331 s.append(Str::binaryToHex(byte), " ");
332 } else
333 s.append(std::string(column_size, ' '), " ");
334
335 if (save_string)
336 output_string += s;
337 std::string current_byte_color = byteColor(byte_offset - shift, region);
338 if (write_to_console) {
339 if (colored_output)
341 else
342 std::cout << s.str();
343 }
344 if (colored_output)
346 if (std::isalnum(byte))
347 ascii_data += byte;
348 else
349 ascii_data += '.';
350 if (colored_output) {
353 }
354 // compute type value (if any)
355 if (show_type_values) {
356 if (colored_output)
358 type_values +=
359 typeValue(byte_offset - shift, reinterpret_cast<u8 *>(aligned_base_address + byte_offset), region);
360 if (colored_output) {
363 }
364 type_values += " ";
365 }
366 }
367 if (show_ascii) {
369 std::cout << "\t|" << ascii_data << "|";
370 if (save_string)
371 output_string.append("\t|", ascii_data, "|");
372 }
373 if (show_type_values) {
375 std::cout << "\t<" << type_values << ">";
376 if (save_string)
377 output_string.append("\t<", type_values, ">");
378 }
379 }
380 if (save_string)
381 output_string += '\n';
383 std::cout << "\n";
384 return output_string.str();
385 }
386
387private:
388 static std::string byteColor(std::size_t byte_index, const RegionLayout &region) {
389 std::function<std::string(const std::vector<RegionLayout> &, std::size_t, const std::string &)> f;
390 f = [&](const std::vector<RegionLayout> &subregions, std::size_t byte_offset,
391 const std::string &parent_color) -> std::string {
392 for (const auto &sub_region : subregions) {
393 auto region_start = sub_region.offset;
394 auto region_end = region_start + sub_region.field_size_in_bytes * sub_region.count;
396 if (sub_region.sub_regions.empty()) {
397 // in the case of an array of elements, lets alternate between dimmed
398 // colors to make it easy to visually identify elements
399 if (((byte_offset - region_start) / sub_region.field_size_in_bytes) % 2)
401 return sub_region.color;
402 }
403 return f(sub_region.sub_regions,
404 (byte_offset - region_start) % sub_region.field_size_in_bytes,
405 sub_region.color);
406 }
407 }
408 return parent_color;
409 };
410 return f({region}, byte_index, ConsoleColors::default_color);
411 }
412
413 static std::string typeValue(std::size_t byte_index, u8 *data, const RegionLayout &region) {
414 std::function<std::string(const std::vector<RegionLayout> &, std::size_t, const std::string &)> f;
415 f = [&](const std::vector<RegionLayout> &subregions, std::size_t byte_offset,
416 const std::string &parent_color) -> std::string {
417 HERMES_UNUSED_VARIABLE(parent_color);
418 for (const auto &sub_region : subregions) {
419 auto region_start = sub_region.offset;
420 auto region_end = region_start + sub_region.field_size_in_bytes * sub_region.count;
421 if (byte_offset >= region_start && byte_offset < region_end) {
422 if (sub_region.sub_regions.empty() && sub_region.type != DataType::CUSTOM) {
423 if ((byte_offset - region_start) % DataTypes::typeSize(sub_region.type) == 0) {
424 std::stringstream ss;
425#define RETURN_TYPE(T) if(sub_region.type == DataTypes::typeFrom<T>()) { \
426 ss << std::setw(10) << std::right << std::setprecision(3) << *reinterpret_cast<T*>(data); \
427 return ss.str(); }
428 RETURN_TYPE(i8)
429 RETURN_TYPE(i16)
430 RETURN_TYPE(i32)
431 RETURN_TYPE(i64)
432 RETURN_TYPE(u8)
433 RETURN_TYPE(u16)
434 RETURN_TYPE(u32)
435 RETURN_TYPE(u64)
436 RETURN_TYPE(f32)
437 RETURN_TYPE(f64)
438#undef RETURN_TYPE
439 return "ERROR";
440 }
441 return "";
442 }
443 return f(sub_region.sub_regions,
444 (byte_offset - region_start) % sub_region.field_size_in_bytes,
445 sub_region.color);
446 }
447 }
448 return "";
449 };
450 return f({region}, byte_index, ConsoleColors::default_color);
451 }
452
453};
454
459inline std::ostream &operator<<(std::ostream &os, const MemoryDumper::RegionLayout &layout) {
460 os << layout.color << "MemoryRegionLayout [offset = " << layout.offset;
461 os << " field size (bytes) = " << layout.field_size_in_bytes;
462 os << " count = " << layout.count;
463 os << " type = " << DataTypes::typeName(layout.type) << "]\n";
464 os << "\tsub regions [" << layout.sub_regions.size() << "]\n";
465 if (!layout.sub_regions.empty())
466 for (const auto &s : layout.sub_regions) {
467 os << s;
468 os << "\n";
469 }
470 os << "\n";
471 return os;
472}
473
474}
475
476#endif //HERMES_HERMES_HERMES_LOG_MEMORY_DUMP_H
477
Support of bitwise operations for compatible enum classes.
#define HERMES_MASK_BIT(MASK, BIT)
Tests if enum class value is enabled.
Definition bitmask_operators.h:84
#define HERMES_ENABLE_BITMASK_OPERATORS(x)
Adds bitwise operation support to a given enum class.
Definition bitmask_operators.h:58
static std::string combine(const std::string &a, const std::string &b)
Combine two color codes.
Definition console_colors.h:112
static char bold[5]
"\e[1m"
Definition console_colors.h:46
static char reset[5]
"\e[0m"
Definition console_colors.h:53
static char dim[5]
"\e[2m"
Definition console_colors.h:47
static char reset_dim[6]
"\e[22m"
Definition console_colors.h:55
static char default_color[6]
"\e[39m"
Definition console_colors.h:61
static std::string typeName(DataType type)
Gets DataType string name.
Definition defs.h:183
static u32 typeSize(DataType type)
Computes number of bytes from DataType.
Definition defs.h:163
Auxiliary logging class for printing blocks of memory.
Definition memory_dump.h:71
static std::string dump(const T *data, std::size_t size, u32 bytes_per_row=8, const RegionLayout &region=RegionLayout(), memory_dumper_options options=memory_dumper_options::none)
Dumps memory region.
Definition memory_dump.h:239
static std::string dumpInfo(const T *data, std::size_t size)
Dumps memory info about a given memory region.
Definition memory_dump.h:214
String class and set of string functions.
Definition str.h:53
static std::string binaryToHex(T input_n, bool uppercase=true, bool strip_leading_zeros=false)
Get ascii representation of raw bit data of input_n
Definition str.h:267
static std::string addressOf(uintptr_t ptr, u32 digit_count=8)
Generates hexadecimal representation of memory address.
Definition str.h:291
static std::string byteToBinary(byte b)
Binary representation of byte.
Definition str.h:303
Set of 256-terminal supported color codes.
Debug, logging and assertion macros.
Data type definitions.
DataType
Enum class for integral types.
Definition defs.h:101
@ none
default behaviour
int8_t i8
8 bit size integer type
Definition defs.h:81
uint64_t u64
64 bit size unsigned integer type
Definition defs.h:89
#define HERMES_UNUSED_VARIABLE(x)
Specifies that variable is not used in this scope.
Definition debug.h:62
uint8_t byte
unsigned byte
Definition defs.h:96
uint16_t u16
16 bit size unsigned integer type
Definition defs.h:87
uint32_t u32
32 bit size unsigned integer type
Definition defs.h:88
int64_t i64
64 bit size integer type
Definition defs.h:84
int16_t i16
16 bit size integer type
Definition defs.h:82
uint8_t u8
8 bit size unsigned integer type
Definition defs.h:86
double f64
64 bit size floating point type
Definition defs.h:79
float f32
32 bit size floating point type
Definition defs.h:78
int32_t i32
32 bit size integer type
Definition defs.h:83
memory_dumper_options
MemoryDumper output options.
Definition memory_dump.h:49
@ hexadecimal
output memory contents in hexadecimal
@ hexii
output memory contents in hexii
@ cache_align
aligns starting address to cache size
@ write_to_console
directly dump into stdout
@ binary
output memory contents in binary
@ decimal
output memory contents in decimal
@ hide_zeros
do not output bytes with 0 as value
@ save_to_string
redirect output to string
@ type_values
cast values and output their values properly
@ hide_header
hide memory column names
@ show_ascii
show ascii characters for each memory byte
@ colored_output
use terminal colors
Number functions.
String utils.
Holds 2-dimensional integer index coordinates.
Definition index.h:50
Memory region description.
Definition memory_dump.h:97
std::size_t count
Region count.
Definition memory_dump.h:199
void pushSubRegion(const RegionLayout &sub_region, bool increment_to_parent_size=false)
Appends a layout representing a sub-region of this layout.
Definition memory_dump.h:145
RegionLayout & withSize(std::size_t size_in_bytes, std::size_t element_count=1)
Modifies layout size based on given quantities.
Definition memory_dump.h:176
void clear()
Removes all description.
Definition memory_dump.h:193
RegionLayout & withColor(const std::string &console_color)
Modifies layout color.
Definition memory_dump.h:110
std::size_t sizeInBytes() const
Gets layout size in bytes.
Definition memory_dump.h:183
void resizeSubRegions(size_t sub_regions_count)
Resizes number of sub-regions of this layout.
Definition memory_dump.h:186
DataType type
Base data type.
Definition memory_dump.h:202
RegionLayout & withSizeOf(std::size_t element_count=1)
Modifies layout size based on given type and count.
Definition memory_dump.h:167
RegionLayout & withOffset(std::size_t offset_in_bytes)
Modifies layout offset.
Definition memory_dump.h:103
RegionLayout & withCount(std::size_t region_count)
Modifies layout count.
Definition memory_dump.h:117
RegionLayout & withTypeFrom()
Modifies layout base data type based on a given type.
Definition memory_dump.h:158
std::string color
Region color.
Definition memory_dump.h:200
RegionLayout & withSubRegion(const RegionLayout &sub_region, bool increment_to_parent_size=false)
Appends a layout representing a sub-region of this layout.
Definition memory_dump.h:132
std::vector< RegionLayout > sub_regions
Sub-region descriptions.
Definition memory_dump.h:201
RegionLayout()=default
Default constructor.
std::size_t field_size_in_bytes
Region size.
Definition memory_dump.h:198
RegionLayout & withType(DataType t)
Modifies layout base data type.
Definition memory_dump.h:124
std::size_t offset
Layout offset in bytes.
Definition memory_dump.h:197
static HERMES_DEVICE_CALLABLE u8 countHexDigits(T n)
Counts hexadecimal digits.
Definition numeric.h:161