/***************************************************************/
/* perk: PE Resource Kit */
/* Copyright (C) 2015--2017 Z. Gilboa */
/* Released under GPLv2 and GPLv3; see COPYING.PERK. */
/***************************************************************/
#include <stddef.h>
#include <string.h>
#include <perk/perk.h>
#include "perk_hdrdump_impl.h"
#define PE_TABWIDTH 8
#define PE_HDRSPACE 40
static const char pe_hex_header_hex[] =
" 0 1 2 3 4 5 6 7 8 9 a b c d e f 01234567 89abcdef\n";
static const char pe_hex_header_dot[] =
" .-------------------------------------------------. .-----------------.\n";
static const char pe_hex_footer[] =
"|---------------------------------------------------| |-----------------|\n\n";
size_t pe_output_hex_header(
char * buf,
const char * sname,
uint64_t faddr,
uint64_t vaddr,
int bits)
{
char * ch;
size_t hlen;
size_t dlen;
size_t slen;
size_t nlen;
uint32_t high;
uint32_t low;
ch = buf;
hlen = strlen(pe_hex_header_hex);
dlen = strlen(pe_hex_header_dot);
slen = strlen(sname);
switch (bits) {
case 32:
low = faddr;
nlen = sprintf(ch,"faddr: 0x%08x\n",low);
break;
case 64:
low = faddr;
high = faddr >> 32;
nlen = sprintf(ch,"faddr: 0x%08x%08x\n",high,low);
break;
default:
return -1;
}
ch += nlen;
switch (bits) {
case 32:
low = vaddr;
nlen = sprintf(ch,"vaddr: 0x%08x",low);
break;
default:
low = vaddr;
high = vaddr >> 32;
nlen = sprintf(ch,"vaddr: 0x%08x%08x",high,low);
break;
}
ch += nlen;
memset(ch,' ',PE_HDRSPACE - nlen);
ch += PE_HDRSPACE - nlen;
memcpy(ch,pe_hex_header_hex,hlen);
ch += hlen;
memcpy(ch,sname,slen);
ch += slen;
memset(ch,' ',PE_HDRSPACE - slen);
ch += PE_HDRSPACE - slen;
memcpy(ch,pe_hex_header_dot,dlen);
ch += dlen;
return ch - buf;
}
size_t pe_output_hex_footer(char * buf)
{
size_t nlen;
memset(buf,' ',PE_HDRSPACE);
buf += PE_HDRSPACE;
nlen = strlen(pe_hex_footer);
memcpy(buf,pe_hex_footer,nlen);
return PE_HDRSPACE + nlen;
}
size_t pe_output_raw_element(
char * ch,
const void * rdata,
const char * mname,
uint32_t moffset,
uint32_t msize)
{
size_t nlen;
char * base;
uintptr_t addr;
const unsigned char * src;
const unsigned char * cap;
const unsigned char * mark;
size_t pos;
size_t xpos;
const char xch[] = "0123456789abcdef";
/* init */
base = ch;
/* pos */
addr = (uintptr_t)rdata;
addr += moffset;
pos = addr % 0x10;
xpos = pos;
/* struct member name */
memset(ch,' ',PE_TABWIDTH);
ch += PE_TABWIDTH;
*ch++ = '.';
nlen = strlen(mname);
memcpy(ch,mname,nlen);
ch += nlen;
*ch++ = ':';
/* hex dump column */
nlen = PE_HDRSPACE - PE_TABWIDTH - nlen - 2;
memset(ch,' ',nlen);
ch += nlen;
*ch++ = '|';
*ch++ = ' ';
nlen = 3 * pos;
memset(ch,' ',nlen);
ch += nlen;
if (pos >= 8) {
*ch++ = ' ';
*ch++ = ' ';
}
/* hex dump */
src = rdata;
src += moffset;
mark = src;
cap = src + msize;
for (; src<cap; ) {
*ch++ = xch[*src / 0x10];
*ch++ = xch[*src % 0x10];
*ch++ = ' ';
/* pretty columns */
if (pos == 7) {
*ch++ = ' ';
*ch++ = ' ';
}
/* binary dump needed? */
if ((++src == cap) || (pos == 0xf)) {
/* binary dump column */
nlen = 3 * (0xf - pos);
nlen += (pos < 7) ? 2 : 0;
memset(ch,' ',nlen);
ch += nlen;
*ch++ = '|';
*ch++ = ' '; *ch++ = ' '; *ch++ = ' ';
*ch++ = ' '; *ch++ = ' '; *ch++ = ' ';
*ch++ = '|';
nlen = xpos + (xpos >= 7);
memset(ch,' ',nlen);
ch += nlen;
/* binary dump */
for (; mark<src; ) {
*ch++ = (*mark >= 0x20) && (*mark < 0x7f)
? *mark : '.';
/* pretty columns */
if ((++mark < src) && (++xpos == 8)) {
*ch++ = ' ';
xpos = 0;
}
}
nlen = 0xf - pos;
nlen += (pos <= 7);
memset(ch,' ',nlen);
ch += nlen;
*ch++ = '|';
*ch++ = '\n';
}
/* does member hex dump span across more than one line? */
if ((src < cap) && (++pos == 0x10)) {
memset(ch,' ',PE_HDRSPACE);
ch += PE_HDRSPACE;
*ch++ = '|';
*ch++ = ' ';
mark = src;
pos = 0;
xpos = 0;
}
}
return ch - base;
}