Memory Dump to outstream






4.90/5 (18 votes)
Function and supporting class to write a memory dump with hex values and characters to an output stream
Introduction
This is a simple piece of code which dumps a section of memory - with address, hex values, and characters - to a stream. I've written something like this a lot of times over the years, whenever I've needed a quick memory dump to log during debugging.
I wanted to make it easy to stream out, so I wrote this as a function which takes a memory address and number of bytes and returns an object with those parameters. This object's class has a function to dump the memory, and a befriended output operator that calls it, so the function can be called in a stream sequence.
Code
Since this is something I'd mostly use while debugging, I keep it all in a single header file, to make it easy to add when needed.
#include <iostream>
#include <iomanip>
//! Class to send a memory dump to stream
class mem_dumper
{
public:
//! Constructor
/*! Construct object that can be serialised out to stream
\param address start address of memory to serialise
\param length number of bytes to serialise
*/
mem_dumper(const void* address, size_t length)
: address_(address), length_(length)
{}
private:
// Address of data to dump
const void* address_;
// Number of bytes to dump
size_t length_;
// Give streaming operator access to streaming function
friend std::ostream& operator<<(std::ostream& os, const mem_dumper& md);
// Streaming function
std::ostream& dump(std::ostream& os) const
{
// Save stream state
std::ios state(NULL);
state.copyfmt(os);
os << std::hex << std::setfill('0');
size_t index = 0;
const unsigned char* address = static_cast<const unsigned char*>(address_);
while (index < length_)
{
// Address
os << std::endl << std::setw(8) << (unsigned long)address_ + index;
// Up to 16 bytes per line
size_t width = (length_ - index) > 16 ? 16 : (length_ - index);
// Hex codes
for (size_t i = 0; i < 16; i++ )
{
// Gap after a 0 and 8 characters
if( i % 8 == 0 )
os << ' ';
// Put in filler if we run out of bytes at the end
if( i < width )
os << ' ' << std::setw(2) << std::hex << (unsigned short)address[i+index];
else
os << " ";
}
os << ' ';
// Printable characters
for( size_t i = 0; i < width; i++)
{
if( i % 8 == 0 )
os << ' ';
if( address[i+index] < 32 )
os << '.';
else
os << address[i+index];
}
index += 16;
}
// Restore state
os.copyfmt(state);
return os;
}
};
//! Stream operator for a mem_dumper
/*! Stream operator for a mem_dumper
\param os output stream
\param md mem_dumper object to serialise
\return output stream
*/
std::ostream& operator<<(std::ostream& os, const mem_dumper& md)
{
return md.dump(os);
}
//! Create a mem_dumper which can be serialised
/*! Create a mem_dumper which can be serialised
\param address start address of memory to serialise
\param length number of bytes to serialise
\return mem_dumper object
*/
inline mem_dumper mem_dump(const void* address, size_t length)
{
return mem_dumper(address, length);
}
Using the Code
To use it, simply pass in the address of the data and how many bytes you want to dump into the function, and send it to an output stream:
#include "mem_dump.hpp"
struct ExampleData
{
char text[22];
bool b;
int i;
ExampleData()
{
memcpy(text, "Blabla bla. Blah? Bla!", 22);
b = true;
i = 1234567;
}
} data;
std::cout << mem_dump(&data, sizeof(ExampleData)) << std::endl;
This will produce (address will vary, and the characters representing the int
bytes will vary depending on platform codepage):
0022FAC8 42 6c 61 62 6c 61 20 62 6c 61 2e 20 42 6c 61 68 Blabla b la. Blah
0022FAD8 3f 20 42 6c 61 21 01 cc 87 d6 12 00 ? Bla!.╠ çÍ.
History
- 26th March, 2018: Initial version
- 28th March, 2018: Fixed address printout increment issue in text and downloadable file