Compare commits

...

22 Commits

6
.gitignore vendored

@ -1,4 +1,8 @@
*~
build/
test*
obj/
hexview-*
profile/
perf.*
flamegraph.svg

@ -1,26 +1,108 @@
SRC=$(wildcard src/*.cpp)
INCLUDE =include
CXXFLAGS = -Wall -pedantic --std=gnu++20 $(addprefix -I,$(INCLUDE))
CXXFLAGS+= -flto -felide-constructors -fgraphite -O3
LDFLAGS = -lfmt -O3 -flto
PROJ = hexview
_HX_FEAT?= -DFIXED_ROW_SIZE=24
CXXFLAGS_COMMON = -Wall -pedantic --std=gnu++20 $(addprefix -I,$(INCLUDE)) -felide-constructors -fno-strict-aliasing -fno-exceptions
LDFLAGS_COMMON = -lfmt
CXXFLAGS_DEFAULT = -pipe -O3 -march=native -fgraphite -flto
CXXFLAGS_RELEASE = -fomit-frame-pointer -fmerge-all-constants -fmodulo-sched -funswitch-loops -fsplit-loops
LDFLAGS_DEFAULT = -O3 -flto
CXXFLAGS_DEBUG = -DDEBUG -O0 -g
PROJECT = hexview
OBJ = $(addprefix obj/,$(SRC:.cpp=.o))
.PHONY: all
all: dirs $(PROJ)
### PGO target specific ###
# Number of times to run profiling
PGO_ITERATIONS = 512
# Size in kb of training files
PGO_DATASET_SIZE = $$(( 1024 * 4 ))
PGO_OBJ = $(addprefix profile/,$(SRC:.cpp=.o))
PROF_FLAGS = -fprofile-generate
###
.PHONY: release
release: | dirs $(PROJECT)-release
.PHONY: debug
debug: | dirs $(PROJECT)-debug
.PHONY: pgo
pgo: | dirs $(PROJECT)-pgo
dirs:
@mkdir -p obj/src
@mkdir -p profile/src
obj/%.o: %.cpp
$(CXX) -c $< $(CXXFLAGS) -o $@ $(LDFLAGS)
$(CXX) -c $< $(_HX_FEAT) $(CXXFLAGS) -o $@ $(LDFLAGS)
profile/%.o: %.cpp
$(CXX) -c $< $(_HX_FEAT) $(CXXFLAGS) $(PROF_FLAGS) -o $@ $(LDFLAGS) $(PROF_FLAGS)
$(PROJ): $(OBJ)
$(PROJECT)-release: CXXFLAGS?= $(CXXFLAGS_DEFAULT)
$(PROJECT)-release: LDFLAGS?= $(LDFLAGS_DEFAULT)
$(PROJECT)-release: CXXFLAGS+= $(CXXFLAGS_COMMON)
$(PROJECT)-release: CXXFLAGS+= $(CXXFLAGS_RELEASE)
$(PROJECT)-release: LDFLAGS := $(LDFLAGS_COMMON) $(LDFLAGS)
$(PROJECT)-release: $(OBJ)
$(CXX) $^ $(CXXFLAGS) -o $@ $(LDFLAGS)
strip $@
$(PROJECT)-debug: CXXFLAGS += $(CXXFLAGS_COMMON)
$(PROJECT)-debug: CXXFLAGS += $(CXXFLAGS_DEBUG)
$(PROJECT)-debug: LDFLAGS += $(LDFLAGS_COMMON)
$(PROJECT)-debug: $(OBJ)
$(CXX) $^ $(CXXFLAGS) -o $@ $(LDFLAGS)
pgo-generate: $(PGO_OBJ)
$(CXX) $^ $(CXXFLAGS) $(PROF_FLAGS) -o $@ $(LDFLAGS) $(PROF_FLAGS)
pgo-reset:
find ./profile -name \*.gcda -exec rm {} +
pgo-profile: | pgo-reset pgo-generate
for i in {1..$(PGO_ITERATIONS)}; do \
dd if=/dev/urandom of=/tmp/$(PROJECT)-pgo-test bs=1024 count=$(PGO_DATASET_SIZE) >> /dev/null 2>&1; \
printf "\rIteration $$i / $(PGO_ITERATIONS)"; \
./pgo-generate /tmp/$(PROJECT)-pgo-test > /tmp/$(PROJECT)-pgo-output; \
done
@echo ""
rm /tmp/$(PROJECT)-pgo-test
rm /tmp/$(PROJECT)-pgo-output
rm pgo-generate
pgo-use: CXXFLAGS?= $(CXXFLAGS_DEFAULT)
pgo-use: LDFLAGS?= $(LDFLAGS_DEFAULT)
pgo-use: CXXFLAGS+= $(CXXFLAGS_COMMON)
pgo-use: CXXFLAGS+= $(CXXFLAGS_RELEASE)
pgo-use: LDFLAGS := $(LDFLAGS_COMMON) -lgcov $(LDFLAGS)
pgo-use: PROF_FLAGS = -fprofile-use
pgo-use: $(PGO_OBJ)
$(CXX) $^ $(CXXFLAGS) $(PROF_FLAGS) -o $@ $(LDFLAGS) $(PROF_FLAGS)
$(PROJECT)-pgo: CXXFLAGS?= $(CXXFLAGS_DEFAULT)
$(PROJECT)-pgo: LDFLAGS?= $(LDFLAGS_DEFAULT)
$(PROJECT)-pgo: CXXFLAGS+= $(CXXFLAGS_COMMON)
$(PROJECT)-pgo: CXXFLAGS+= $(CXXFLAGS_RELEASE)
$(PROJECT)-pgo: LDFLAGS := $(LDFLAGS_COMMON) $(LDFLAGS)
$(PROJECT)-pgo: | dirs pgo-profile
find ./profile -name \*.o -exec rm {} +
$(MAKE) pgo-use
mv pgo-use $@
strip $@
clean:
rm -f $(PROJ)
rm -f $(PROJECT)-{release,debug,pgo}
rm -rf obj
rm -rf profile
rm -f pgo-{test,output,generate}

@ -5,4 +5,42 @@
namespace hv {
/// Print a single screen
void print_screen(const span<unsigned char> bytes, unsigned long offset);
inline void lookup_hex_string(std::uint64_t x, char* s)
{
static const char digits[513] =
"000102030405060708090a0b0c0d0e0f"
"101112131415161718191a1b1c1d1e1f"
"202122232425262728292a2b2c2d2e2f"
"303132333435363738393a3b3c3d3e3f"
"404142434445464748494a4b4c4d4e4f"
"505152535455565758595a5b5c5d5e5f"
"606162636465666768696a6b6c6d6e6f"
"707172737475767778797a7b7c7d7e7f"
"808182838485868788898a8b8c8d8e8f"
"909192939495969798999a9b9c9d9e9f"
"a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
"b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
"c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
"d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
"e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff";
int i = 7;
const char *lut = (const char *)digits;
while (i >= 0)
{
int pos = (x & 0xFF) * 2;
char ch = lut[pos];
#ifdef DEBUG
if ( (i*2+1) >=16) std::terminate();
#endif
s[i * 2] = ch;
ch = lut[pos + 1];
s[i * 2 + 1] = ch;
x >>= 8;
i -= 1;
}
}
}

@ -25,12 +25,12 @@ namespace hv
inline byte& operator[](std::size_t index)
{
if (index>=size) throw "tried to index out of bounds of map";
if (index>=size) std::terminate();
return ((byte*)block0)[index];
}
inline const byte& operator[](std::size_t index) const
{
if (index>=size) throw "tried to index out of bounds of map";
if (index>=size) std::terminate();
return ((byte*)block0)[index];
}
@ -64,7 +64,7 @@ namespace hv
inline const byte& operator[](std::size_t index) const
{
if (index>=size) throw "tried to index out of bounds of map";
if (index>=size) std::terminate();
return ((byte*)block0)[index];
}

@ -1,5 +1,6 @@
#pragma once
#include <exception>
#include <cstdint>
#include <cmath>
@ -19,24 +20,28 @@ namespace hv
inline T& operator[](std::size_t index)
{
if (index>=len) throw "tried to index out of bounds of array";
#ifdef DEBUG
if (index>=len) std::terminate(); // "tried to index out of bounds of array";
#endif
return ptr[index];
}
inline const T& operator[](std::size_t index) const
{
if (index>=len) throw "tried to index out of bounds of array";
#ifdef DEBUG
if (index>=len) std::terminate(); // "tried to index out of bounds of array";
#endif
return ptr[index];
}
inline span<T> slice(std::size_t off, std::size_t len)
{
len = std::min(this->len, len);
if(len+off>=len || len < off) throw "tried to index out of bounds of array";
if(len+off>=len || len < off) std::terminate(); // "tried to index out of bounds of array";
return span<T>(ptr+off, len-off);
}
inline span<T> slice(std::size_t off)
{
if(len+off>=len || len < off) throw "tried to index out of bounds of array";
if(len+off>=len || len < off) std::terminate(); // "tried to index out of bounds of array";
return span<T>(ptr+off, len-off);
}

@ -1,5 +1,6 @@
#include <fmt/format.h>
#include <span.hpp>
#include <hex.hpp>
const static constexpr char ascii_map[256] = {
'.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.',
@ -20,43 +21,119 @@ const static constexpr char ascii_map[256] = {
'.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.',
};
constexpr const static char* hex_map[256] = {
"00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0a", "0b", "0c", "0d", "0e", "0f",
"10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1a", "1b", "1c", "1d", "1e", "1f",
"20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2a", "2b", "2c", "2d", "2e", "2f",
"30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3a", "3b", "3c", "3d", "3e", "3f",
"40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "4a", "4b", "4c", "4d", "4e", "4f",
"50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "5a", "5b", "5c", "5d", "5e", "5f",
"60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6a", "6b", "6c", "6d", "6e", "6f",
"70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "7a", "7b", "7c", "7d", "7e", "7f",
"80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "8a", "8b", "8c", "8d", "8e", "8f",
"90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9a", "9b", "9c", "9d", "9e", "9f",
"a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "aa", "ab", "ac", "ad", "ae", "af",
"b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7", "b8", "b9", "ba", "bb", "bc", "bd", "be", "bf",
"c0", "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9", "ca", "cb", "cc", "cd", "ce", "cf",
"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "da", "db", "dc", "dd", "de", "df",
"e0", "e1", "e2", "e3", "e4", "e5", "e6", "e7", "e8", "e9", "ea", "eb", "ec", "ed", "ee", "ef",
"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "fa", "fb", "fc", "fd", "fe", "ff",
};
#ifndef FIXED_ROW_SIZE
#include <alloca.h>
#endif
#ifdef FIXED_ROW_SIZE
constexpr int ROW_SZ = FIXED_ROW_SIZE;
constexpr const int ROW_SZ = FIXED_ROW_SIZE;
#endif
template<typename... S>
inline __attribute__((always_inline)) void prints(const S&... strings)
{
(fputs((const char*)strings, stdout), ...);
}
inline void hex02(std::uint8_t byte, char buffer[2])
{
buffer[0] =hex_map[byte][0];
buffer[1] =hex_map[byte][1];
}
template<std::size_t N>
inline __attribute__((always_inline)) void print_exact(const char* ar)
{
fwrite(ar, 1, N, stdout);
}
template<std::size_t N>
inline __attribute__((always_inline)) void print_exact(const char (&ar)[N])
{
fwrite(ar, N, 1, stdout);
}
inline static void u64_to_hex(std::uint64_t num, char* s)
{
hv::lookup_hex_string(num, s);
}
namespace hv {
void print_screen(const span<unsigned char> memory, unsigned long offset)
{
void print_screen(const span<unsigned char> memory, unsigned long offset)
{
#ifndef FIXED_ROW_SIZE
#define S (const char*)
int ROW_SZ = 24;
#define S (2+ROW_SZ)
#define P_EX(n, buf) fwrite(buf, 1, n, stdout)
int ROW_SZ = 24;
#else
#define S
#define P_EX(n, buf) print_exact(buf)
#endif
fmt::print("0x{:016x} ", offset);
char ascii[1 + ROW_SZ];
ascii[ROW_SZ] = 0;
std::size_t i=0;
for(;i<memory.size();i++) {
if (i && i % ROW_SZ == 0) {
fmt::print(" {}", S ascii);
fmt::print("\n0x{:016x} ", i+offset);
}
fmt::print("{:02x} ", memory[i]);
ascii[i%ROW_SZ] = ascii_map[memory[i]];
}
if (memory.size() % ROW_SZ != 0)
{
auto rest = memory.size() % ROW_SZ;
ascii[rest] = 0;
for(std::size_t j=0;j< ROW_SZ - rest;j++)
fmt::print(" ");
}
fmt::print(" {}", S ascii);
}
char posbuf[3 + 16 + 2];
posbuf[0] = '\n';
posbuf[1] = '0';
posbuf[2] = 'x';
#ifdef DEBUG
std::memset(posbuf+3, '0', 16);
#endif
posbuf[3 + 16] = ' ';
posbuf[3 + 16 + 1] = ' ';
u64_to_hex(offset, posbuf+3);
prints(posbuf+1);
char hxbuf[3] = { ' ', ' ', ' ' };
std::size_t i=0;
char r_ascii[2 + ROW_SZ];
r_ascii[0] = ' ';
r_ascii[1] = ' ';
char* ascii = r_ascii + 2;
const auto memsize = memory.size();
for(;i<memsize;i++) {
if (i && i % ROW_SZ == 0) { //TODO: Change to i +=16 so we don't have to branch here on every byte. Make sure to not overrun buffer tho
P_EX(S, r_ascii);
u64_to_hex(i+offset, posbuf+3);
print_exact(posbuf);
}
unsigned char idx = memory[i];
hex02(idx, hxbuf);
print_exact(hxbuf);
ascii[i%ROW_SZ] = ascii_map[idx];
}
if (memsize % ROW_SZ != 0)
{
auto rest = memsize % ROW_SZ;
ascii[rest] = 0;
constexpr const char output[3] = { ' ', ' ', ' ' };
for(std::size_t j=0;j< ROW_SZ - rest;j++)
print_exact(output);
prints((const char*) r_ascii);
}
else {
P_EX(S, r_ascii);
}
}
}

@ -9,12 +9,12 @@ namespace hv
memory_map::memory_map(std::uint64_t size, int&& fd) noexcept
: is_cow(false), size(size), fd(fd), block0(mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0))
{
if(!block0) throw "memory_map failed";
if(!block0) std::terminate();
}
memory_map::memory_map(std::uint64_t size, int&& fd, bool _cow) noexcept
: is_cow(true), size(size), fd(fd), block0(mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0))
{
if(!block0) throw "memory_map::cow failed";
if(!block0) std::terminate();
}
memory_map::memory_map(std::uint64_t size, const char* file) noexcept
: memory_map(size, open(file, O_RDWR)) {}

Loading…
Cancel
Save