Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Memory Dump to outstream

0.00/5 (No votes)
4 Apr 2018 1  
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

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here