redo hexDump

ludicrously inefficient (cf. toHex() ), and inflexible.
This commit is contained in:
Michael Davidsaver
2019-03-06 10:32:53 -08:00
parent 732fd1f771
commit ecee708d3a
7 changed files with 121 additions and 157 deletions

View File

@ -4,8 +4,6 @@
* in file LICENSE that is included with this distribution.
*/
#include <sstream>
#include <osiSock.h>
#include <pv/byteBuffer.h>
@ -15,9 +13,6 @@
#include <pv/remote.h>
#include <pv/hexDump.h>
using std::ostringstream;
using std::hex;
using namespace epics::pvData;
namespace epics {
@ -44,13 +39,10 @@ void ResponseHandler::handleResponse(osiSockAddr* responseFrom,
char ipAddrStr[48];
ipAddrToDottedIP(&responseFrom->ia, ipAddrStr, sizeof(ipAddrStr));
ostringstream prologue;
prologue<<"Message [0x"<<hex<<(int)command<<", v0x"<<hex;
prologue<<(int)version<<"] received from "<<ipAddrStr<<" on "<<transport->getRemoteName();
hexDump(prologue.str(), _description,
(const int8*)payloadBuffer->getArray(),
payloadBuffer->getPosition(), static_cast<int>(payloadSize));
std::cerr<<"Message [0x"<<std::hex<<(int)command<<", v0x"<<std::hex
<<int(version)<<"] received from "<<ipAddrStr<<" on "<<transport->getRemoteName()
<<" : "<<_description<<"\n"
<<HexDump(*payloadBuffer, payloadSize);
}
}
}

View File

@ -185,12 +185,6 @@ void AbstractCodec::processReadNormal() {
return;
}
/*
hexDump("Header", (const int8*)_socketBuffer.getArray(),
_socketBuffer.getPosition(), PVA_MESSAGE_HEADER_SIZE);
*/
// read header fields
processHeader();
bool isControl = ((_flags & 0x01) == 0x01);
@ -797,14 +791,6 @@ void AbstractCodec::send(ByteBuffer *buffer)
//int p = buffer.position();
int bytesSent = write(buffer);
/*
if (IS_LOGGABLE(logLevelTrace)) {
hexDump(std::string("AbstractCodec::send WRITE"),
(const int8 *)buffer->getArray(),
buffer->getPosition(), buffer->getRemaining());
}
*/
if (bytesSent < 0)
{
// connection lost
@ -1302,13 +1288,6 @@ int BlockingTCPTransportCodec::read(epics::pvData::ByteBuffer* dst) {
// NOTE: do not log here, you might override SOCKERRNO relevant to recv() operation above
/*
if (IS_LOGGABLE(logLevelTrace)) {
hexDump(std::string("READ"),
(const int8 *)(dst->getArray()+pos), bytesRead);
}
*/
if(unlikely(bytesRead<=0)) {
if (bytesRead<0)

View File

@ -2998,10 +2998,14 @@ public:
{
if (command < 0 || command >= (int8)m_handlerTable.size())
{
// TODO remove debug output
char buf[100];
sprintf(buf, "Invalid (or unsupported) command %d, its payload", command);
hexDump(buf, (const int8*)(payloadBuffer->getArray()), payloadBuffer->getPosition(), payloadSize);
LOG(logLevelError,
"Invalid (or unsupported) command: %x.", (0xFF&command));
if(pvAccessIsLoggable(logLevelError)) {
std::cerr<<"Invalid PVA header "<<hex<<(int)(0xFF&command)
<<", its payload buffer\n"
<<HexDump(*payloadBuffer, payloadSize);
}
return;
}
// delegate

View File

@ -155,16 +155,14 @@ void ServerResponseHandler::handleResponse(osiSockAddr* responseFrom,
{
if(command<0||command>=(int8)m_handlerTable.size())
{
LOG(logLevelDebug,
LOG(logLevelError,
"Invalid (or unsupported) command: %x.", (0xFF&command));
// TODO remove debug output
std::ostringstream name;
name<<"Invalid PVA header "<<hex<<(int)(0xFF&command);
name<<", its payload buffer";
hexDump(name.str(), (const int8*)payloadBuffer->getArray(),
payloadBuffer->getPosition(), payloadSize);
if(pvAccessIsLoggable(logLevelError)) {
std::cerr<<"Invalid PVA header "<<hex<<(int)(0xFF&command)
<<", its payload buffer\n"
<<HexDump(*payloadBuffer, payloadSize);
}
return;
}

View File

@ -7,102 +7,92 @@
#include <iostream>
#include <sstream>
#include <string>
#include <iomanip>
#include <algorithm>
#include <pv/byteBuffer.h>
#define epicsExportSharedSymbols
#include <pv/hexDump.h>
using namespace epics::pvData;
using std::string;
using std::stringstream;
using std::endl;
using std::cout;
namespace epics {
namespace pvAccess {
/// Byte to hexchar mapping.
static const char lookup[] = {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};
HexDump::HexDump(const char* buf, size_t len)
:buf(buf)
,buflen(len)
,_limit(1024u)
,_groupBy(4u)
,_perLine(16u)
{}
/// Get hex representation of byte.
string toHex(int8 b) {
string sb;
int upper = (b>>4)&0x0F;
sb += lookup[upper];
int lower = b&0x0F;
sb += lookup[lower];
sb += ' ';
return sb;
HexDump::HexDump(const pvData::ByteBuffer& bb,
size_t size, size_t offset)
:buf(bb.getBuffer() + bb.getPosition())
,buflen(bb.getRemaining())
,_limit((size_t)-1)
,_groupBy(4u)
,_perLine(16u)
{
if(offset > buflen)
offset = buflen;
buf += offset;
buflen -= offset;
if(buflen > size)
buflen = size;
}
/// Get ASCII representation of byte, dot if non-readable.
char toAscii(int8 b) {
if(b>(int8)31&&b<(int8)127)
return (char)b;
else
return '.';
HexDump::~HexDump() {}
static
size_t ilog2(size_t val)
{
size_t ret = 0;
while(val >>= 1)
ret++;
return ret;
}
void hexDump(std::string const & name, const int8 *bs, int len) {
hexDump(name, bs, 0, len);
static
size_t bits2bytes(size_t val)
{
// round up to next multiple of 8
val -= 1u;
val |= 7u;
val += 1u;
// bits -> bytes
val /= 8u;
return val;
}
void hexDump(std::string const & name, const int8 *bs, int start, int len) {
hexDump("", name, bs, start, len);
}
epicsShareFunc
std::ostream& operator<<(std::ostream& strm, const HexDump& hex)
{
size_t len = std::min(hex.buflen, hex._limit);
// find address width in hex chars
// find bit width, rounded up to 8 bits, divide down to bytes
size_t addrwidth = bits2bytes(ilog2(len))*2u;
void hexDump(std::string const & prologue, string const & name, const int8 *bs,
int start, int len) {
for(size_t i=0; i<len; i++)
{
unsigned val = hex.buf[i]&0xff;
size_t col = i%hex._perLine;
stringstream header;
header<<prologue<<endl<<"Hexdump ["<<name<<"] size = "<<len;
string out(header.str());
string chars;
for(int i = start; i<(start+len); i++) {
if(((i-start)%16)==0) {
out += chars;
out += '\n';
chars.erase();
if(col==0) {
// first address of this row
strm<<"0x"<<std::hex<<std::setw(addrwidth)<<std::setfill('0')<<i;
}
chars += toAscii(bs[i]);
out += toHex(bs[i]);
if(((i-start)%4)==3) {
chars += ' ';
out += ' ';
if(col%hex._groupBy == 0) {
strm<<' ';
}
strm<<std::hex<<std::setw(2)<<std::setfill('0')<<val;
if(col+1u==hex._perLine && i+1u!=len)
strm<<'\n';
}
if(len%16!=0) {
int pad = 0;
int delta_bytes = 16-(len%16);
//rest of line (no of bytes)
//each byte takes two chars plus one ws
pad = delta_bytes*3;
//additional whitespaces after four bytes
pad += (delta_bytes/4);
pad++;
for(int i = 0; i<pad; i++)
chars.insert(0, " ");
}
out += chars;
cout<<out<<endl;
if(len==hex._limit && len<hex.buflen)
strm<<" ...";
strm<<'\n';
return strm;
}
}

View File

@ -7,6 +7,8 @@
#ifndef HEXDUMP_H_
#define HEXDUMP_H_
#include <ostream>
#ifdef epicsExportSharedSymbols
# define hexDumpEpicsExportSharedSymbols
# undef epicsExportSharedSymbols
@ -22,35 +24,34 @@
#include <shareLib.h>
namespace epics {
namespace pvData {
class ByteBuffer;
}
namespace pvAccess {
/**
* Output a buffer in hex format.
* @param name name (description) of the message.
* @param bs buffer to dump
* @param len first bytes (length) to dump.
*/
epicsShareFunc void hexDump(std::string const & name, const epics::pvData::int8 *bs, int len);
class epicsShareClass HexDump {
const char* buf;
size_t buflen;
size_t _limit;
unsigned _groupBy;
unsigned _perLine;
public:
HexDump(const char* buf, size_t len);
explicit HexDump(const pvData::ByteBuffer& buf, size_t size=(size_t)-1, size_t offset=0u);
~HexDump();
/**
* Output a buffer in hex format.
* @param[in] name name (description) of the message.
* @param[in] bs buffer to dump
* @param[in] start dump message using given offset.
* @param[in] len first bytes (length) to dump.
*/
epicsShareFunc void hexDump(std::string const & name, const epics::pvData::int8 *bs, int start, int len);
//! safety limit on max bytes printed
inline HexDump& limit(size_t n=(size_t)-1) { _limit = n; return *this; }
//! insert a space after this many bytes
inline HexDump& bytesPerGroup(size_t n=(size_t)-1) { _groupBy = n; return *this; }
//! start a new line after this many bytes
inline HexDump& bytesPerLine(size_t n=(size_t)-1) { _perLine = n; return *this; }
/**
* Output a buffer in hex format.
* @param[in] prologue string to prefixed to debug output, can be <code>null</code>
* @param[in] name name (description) of the message.
* @param[in] bs buffer to dump
* @param[in] start dump message using given offset.
* @param[in] len first bytes (length) to dump.
*/
epicsShareFunc void hexDump(std::string const & prologue, std::string const & name,
const epics::pvData::int8 *bs, int start, int len);
friend std::ostream& operator<<(std::ostream& strm, const HexDump& hex);
};
epicsShareFunc
std::ostream& operator<<(std::ostream& strm, const HexDump& hex);
}
}

View File

@ -1,6 +1,9 @@
#include <epicsUnitTest.h>
#include <sstream>
#include <testMain.h>
#include <pv/pvUnitTest.h>
#include <pv/hexDump.h>
using namespace epics::pvData;
@ -8,19 +11,16 @@ using namespace epics::pvAccess;
MAIN(testHexDump)
{
testPlan(3);
testPlan(1);
testDiag("Tests for hexDump");
char TO_DUMP[] = "pvAccess dump test\0\1\2\3\4\5\6\254\255\256";
char TO_DUMP[] = "pvAccess dump test\0\1\2\3\4\5\6\xfd\xfe\xff";
hexDump("test", (int8*)TO_DUMP, 18+9);
testPass("Entire array");
std::ostringstream msg;
msg<<HexDump(TO_DUMP, sizeof(TO_DUMP)-1);
hexDump("only text", (int8*)TO_DUMP, 18);
testPass("Only text");
hexDump("22 byte test", (int8*)TO_DUMP, 22);
testPass("22 bytes test");
testEqual(msg.str(), "0x00 70764163 63657373 2064756d 70207465\n"
"0x10 73740001 02030405 06fdfeff\n");
return testDone();
}