Skip to content

Instantly share code, notes, and snippets.

@Autoplay1999
Last active December 28, 2025 14:17
Show Gist options
  • Select an option

  • Save Autoplay1999/f454d414d6b36ff110b94bfe242f5c52 to your computer and use it in GitHub Desktop.

Select an option

Save Autoplay1999/f454d414d6b36ff110b94bfe242f5c52 to your computer and use it in GitHub Desktop.
Gemini + Grok
#pragma once
#include <windows.h>
#include <cstdint>
#include <cstddef>
#include <array>
#include <vector>
#include <string>
#include <string_view>
#include <memory>
#include <atomic>
#include <mutex>
#include <chrono>
#include <unordered_map>
#include <thread>
#include <fstream>
#include <algorithm>
#include <cstdio>
#include <cstdarg>
#include <cstring>
#include <stdexcept>
namespace tl {
constexpr uint64_t BLOCK_SIGNATURE = 0x544C4F47524F4B58ULL;
constexpr size_t MAX_MESSAGE_LEN = 8192;
constexpr size_t MAX_CALLSTACK_DEPTH = 256;
constexpr size_t RING_BUFFER_SIZE = 8192;
constexpr double ALPHA_WEIGHT = 0.1;
#pragma pack(push, 1)
struct LogEntryHeader {
uint64_t signature{ BLOCK_SIGNATURE };
uint8_t version{ 1 };
uint8_t level{};
uint64_t status{};
uint32_t thread_id{};
int64_t timestamp_us{};
uint16_t callstack_count{};
uint16_t message_len{};
};
#pragma pack(pop)
constexpr size_t MAX_BLOCK_SIZE = sizeof(uint64_t) + sizeof(uint64_t) +
sizeof(LogEntryHeader) +
(sizeof(uint16_t) + MAX_CALLSTACK_DEPTH * (sizeof(uint32_t) + sizeof(uint16_t))) +
(sizeof(uint16_t) + MAX_MESSAGE_LEN);
class LogEntryConverter {
public:
virtual bool convert(uint8_t* payload_start, size_t payload_size) noexcept = 0;
};
class PlainConverter : public LogEntryConverter {
public:
bool convert(uint8_t* payload_start, size_t payload_size) noexcept override { return true; }
};
class EncryptConverter : public LogEntryConverter {
static constexpr std::array<uint8_t, 32> key = { 0xac, 0x0a, 0xb0, 0xeb, 0x54, 0xee, 0x88, 0xe4, 0xea, 0x13, 0x89, 0x3a, 0xc1, 0x29, 0x0f, 0x24, 0x02, 0x15, 0xcf, 0x71, 0xab, 0x51, 0x3b, 0xda, 0x11, 0xde, 0x0f, 0xb1, 0xcd, 0xa9, 0xe4, 0x70 };
static constexpr std::array<uint8_t, 12> nonce = { 0x75, 0xa3, 0xed, 0x51, 0x79, 0x84, 0xc7, 0xfa, 0x4b, 0x9e, 0xb7, 0xc2 };
bool convert(uint8_t* payload_start, size_t payload_size) noexcept override {
ChaCha20 chacha20;
chacha20.crypt(key.data(), key.size(), nonce.data(), nonce.size(), payload_start, payload_size);
return true;
}
class ChaCha20 {
private:
static constexpr std::array<uint32_t, 4> sigma = { 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 };
static uint32_t rotl(uint32_t x, int b) noexcept {
return (x << b) | (x >> (32 - b));
}
static void quarter_round(uint32_t& a, uint32_t& b, uint32_t& c, uint32_t& d) noexcept {
a += b; d ^= a; d = rotl(d, 16);
c += d; b ^= c; b = rotl(b, 12);
a += b; d ^= a; d = rotl(d, 8);
c += d; b ^= c; b = rotl(b, 7);
}
static void chacha_block(std::array<uint32_t, 16>& state) noexcept {
auto x = state;
for (int i = 0; i < 10; ++i) { // 20 rounds (10 double rounds)
quarter_round(x[0], x[4], x[8], x[12]);
quarter_round(x[1], x[5], x[9], x[13]);
quarter_round(x[2], x[6], x[10], x[14]);
quarter_round(x[3], x[7], x[11], x[15]);
quarter_round(x[0], x[5], x[10], x[15]);
quarter_round(x[1], x[6], x[11], x[12]);
quarter_round(x[2], x[7], x[8], x[13]);
quarter_round(x[3], x[4], x[9], x[14]);
}
for (int i = 0; i < 16; ++i) {
x[i] += state[i];
state[i] = x[i];
}
}
static void serialize(uint32_t v, uint8_t* out) noexcept {
out[0] = static_cast<uint8_t>(v);
out[1] = static_cast<uint8_t>(v >> 8);
out[2] = static_cast<uint8_t>(v >> 16);
out[3] = static_cast<uint8_t>(v >> 24);
}
static uint32_t load_le(const uint8_t* in) noexcept {
return static_cast<uint32_t>(in[0])
| (static_cast<uint32_t>(in[1]) << 8)
| (static_cast<uint32_t>(in[2]) << 16)
| (static_cast<uint32_t>(in[3]) << 24);
}
public:
static uint8_t* crypt(const uint8_t* key, size_t key_len,
const uint8_t* nonce, size_t nonce_len,
uint8_t* in, size_t in_len) {
if (key_len != 32 || nonce_len != 12) {
throw std::invalid_argument("ChaCha20 requires 32-byte key and 12-byte nonce");
}
std::array<uint32_t, 16> state{};
state[0] = sigma[0];
state[1] = sigma[1];
state[2] = sigma[2];
state[3] = sigma[3];
for (int i = 0; i < 8; ++i) {
state[4 + i] = load_le(key + 4 * i);
}
state[12] = 0;
state[13] = load_le(nonce + 0);
state[14] = load_le(nonce + 4);
state[15] = load_le(nonce + 8);
size_t pos = 0;
uint64_t counter = 0;
while (pos < in_len) {
std::array<uint32_t, 16> block_state = state;
block_state[12] = static_cast<uint32_t>(counter);
chacha_block(block_state);
std::array<uint8_t, 64> keystream{};
for (int i = 0; i < 16; ++i) {
serialize(block_state[i], keystream.data() + 4 * i);
}
size_t block_size = std::min<size_t>(64, in_len - pos);
for (size_t i = 0; i < block_size; ++i) {
in[pos + i] = in[pos + i] ^ keystream[i];
}
pos += block_size;
++counter;
}
return in;
}
};
};
inline std::atomic<LogEntryConverter*>& global_encryptor() noexcept {
static EncryptConverter default_instance;
static std::atomic<LogEntryConverter*> instance{ &default_instance };
return instance;
}
struct TimingMeasure {
std::chrono::high_resolution_clock::time_point start{};
double avg_us{ 0.0 };
TimingMeasure() = default;
void begin() noexcept { start = std::chrono::high_resolution_clock::now(); }
void end() noexcept {
auto now = std::chrono::high_resolution_clock::now();
double diff_us = std::chrono::duration<double, std::micro>(now - start).count();
if (avg_us == 0.0) avg_us = diff_us;
else avg_us += ALPHA_WEIGHT * (diff_us - avg_us);
}
double get_average_us() const noexcept { return avg_us; }
};
struct CallEntry {
uint32_t func_id{ 0 };
uint16_t step{ 0 };
bool measure{ false };
TimingMeasure timing{};
CallEntry() = default;
CallEntry(uint32_t fid, bool meas) noexcept : func_id(fid), measure(meas) {
if (meas) timing.begin();
}
};
struct ThreadContext {
std::vector<CallEntry> call_stack;
void push(uint32_t func_id, bool measure = false) noexcept {
call_stack.emplace_back(func_id, measure);
}
void pop() noexcept {
if (!call_stack.empty()) {
auto& callstack = call_stack.back();
if (callstack.measure) {
callstack.timing.end();
}
call_stack.pop_back();
}
}
void set_step(uint16_t s) noexcept {
if (!call_stack.empty()) call_stack.back().step = s;
}
const std::vector<CallEntry>& get_stack() const noexcept { return call_stack; }
};
class ThreadRegistry {
public:
static ThreadRegistry& instance() noexcept {
static ThreadRegistry inst;
return inst;
}
void register_context(DWORD tid, std::shared_ptr<ThreadContext> ctx) noexcept {
std::lock_guard<std::mutex> lk(mutex_);
map_[tid] = std::weak_ptr<ThreadContext>(ctx);
}
void unregister_context(DWORD tid) noexcept {
std::lock_guard<std::mutex> lk(mutex_);
map_.erase(tid);
}
std::vector<std::pair<DWORD, std::shared_ptr<ThreadContext>>> get_active() const noexcept {
std::vector<std::pair<DWORD, std::shared_ptr<ThreadContext>>> result;
std::lock_guard<std::mutex> lk(mutex_);
result.reserve(map_.size());
for (const auto& [tid, weak] : map_) {
if (auto sp = weak.lock()) {
result.emplace_back(tid, std::move(sp));
}
}
return result;
}
uint64_t& main_tid() noexcept { return main_tid_; }
private:
mutable std::mutex mutex_;
uint64_t main_tid_ = 0;
std::unordered_map<DWORD, std::weak_ptr<ThreadContext>> map_;
};
struct ThreadContextManager {
static ThreadContext* get() noexcept {
thread_local std::shared_ptr<ThreadContext> ctx;
thread_local bool initialized = false;
thread_local struct Cleaner {
~Cleaner() {
if (initialized) {
ThreadRegistry::instance().unregister_context(::GetCurrentThreadId());
}
}
} cleaner{};
if (!initialized) {
ctx = std::make_shared<ThreadContext>();
ThreadRegistry::instance().register_context(::GetCurrentThreadId(), ctx);
initialized = true;
}
return ctx.get();
}
};
class LogBlockPool {
public:
enum State : int { Empty = 0, Writing = 1, Ready = 2 };
struct Block {
alignas(64) std::array<std::byte, MAX_BLOCK_SIZE> data;
std::atomic<int> state{ Empty };
};
LogBlockPool() : blocks(std::make_unique<Block[]>(RING_BUFFER_SIZE)) {}
Block* try_claim() noexcept {
size_t wp = write_pos.load(std::memory_order_relaxed);
while (true) {
size_t rp = read_pos.load(std::memory_order_acquire);
if ((wp - rp) >= RING_BUFFER_SIZE) {
dropped_count.fetch_add(1, std::memory_order_relaxed);
return nullptr;
}
if (write_pos.compare_exchange_weak(wp, wp + 1, std::memory_order_acq_rel)) {
break;
}
}
size_t idx = wp & (RING_BUFFER_SIZE - 1);
Block* b = &blocks[idx];
int expected = Empty;
if (b->state.compare_exchange_strong(expected, Writing, std::memory_order_acq_rel)) {
return b;
}
dropped_count.fetch_add(1, std::memory_order_relaxed);
return nullptr;
}
void commit(Block* block) noexcept {
block->state.store(Ready, std::memory_order_release);
committed.fetch_add(1, std::memory_order_release);
}
bool try_dequeue(std::byte*& ptr, size_t& sz) noexcept {
if (committed.load(std::memory_order_acquire) == 0)
return false;
size_t rp = read_pos.load(std::memory_order_relaxed);
size_t idx = rp & (RING_BUFFER_SIZE - 1);
Block& b = blocks[idx];
int state = b.state.load(std::memory_order_acquire);
if (state != Ready)
return false;
ptr = b.data.data();
sz = 0;
b.state.store(Empty, std::memory_order_release);
read_pos.store(rp + 1, std::memory_order_release);
committed.fetch_sub(1, std::memory_order_release);
return true;
}
uint64_t get_dropped_count() const noexcept { return dropped_count.load(); }
size_t get_committed_count() const noexcept { return committed.load(std::memory_order_acquire); }
private:
std::unique_ptr<Block[]> blocks;
alignas(64) std::atomic<size_t> write_pos{ 0 };
alignas(64) std::atomic<size_t> read_pos{ 0 };
alignas(64) std::atomic<size_t> committed{ 0 };
alignas(64) std::atomic<uint64_t> dropped_count{ 0 };
};
class AsyncLogWriter {
public:
enum class Mode { Async, Sync };
static AsyncLogWriter& instance() noexcept {
static AsyncLogWriter writer;
return writer;
}
void initialize(const std::string& filename = "app_trace.bin") noexcept {
std::lock_guard<std::mutex> lk(init_mutex_);
if (initialized_) return;
filename_ = filename;
mode_ = Mode::Async;
handle_ = ::CreateFileA(filename_.c_str(), GENERIC_WRITE, FILE_SHARE_READ, nullptr,
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH, nullptr);
if (handle_ == INVALID_HANDLE_VALUE) {
use_fallback_ = true;
fallback_.open(filename_, std::ios::binary | std::ios::app);
} else {
::SetFilePointer(handle_, 0, nullptr, FILE_END);
}
initialized_ = true;
}
void shutdown() noexcept {
flush();
std::lock_guard<std::mutex> lk(init_mutex_);
if (handle_ != INVALID_HANDLE_VALUE) {
::FlushFileBuffers(handle_);
::CloseHandle(handle_);
handle_ = INVALID_HANDLE_VALUE;
}
if (fallback_.is_open()) fallback_.close();
initialized_ = false;
}
void set_mode(Mode mode) noexcept {
std::lock_guard<std::mutex> lk(init_mutex_);
if (mode_ != mode) {
flush();
mode_ = mode;
}
}
Mode get_mode() noexcept {
std::lock_guard<std::mutex> lk(init_mutex_);
return mode_;
}
void flush() noexcept {
std::vector<std::vector<std::byte>> batches;
{
std::vector<std::byte> batch;
batch.reserve(1024 * 1024);
std::byte* ptr;
size_t dummy_sz;
while (pool_.try_dequeue(ptr, dummy_sz)) {
const uint64_t* sig = reinterpret_cast<const uint64_t*>(ptr);
if (*sig != BLOCK_SIGNATURE) continue;
const uint64_t* total_size_ptr = sig + 1;
uint64_t block_size = *total_size_ptr;
if (block_size <= sizeof(uint64_t) * 2 || block_size > MAX_BLOCK_SIZE) continue;
batch.insert(batch.end(), ptr, ptr + block_size);
if (batch.size() > 4 * 1024 * 1024) {
batches.push_back(std::move(batch));
batch.clear();
batch.reserve(1024 * 1024);
}
}
if (!batch.empty()) {
batches.push_back(std::move(batch));
}
}
if (mode_ == Mode::Sync || batches.size() == 1) {
for (const auto& b : batches) {
write_batch_sync(b);
}
} else {
std::vector<std::thread> workers;
workers.reserve(batches.size());
for (auto& b : batches) {
workers.emplace_back([this, data = std::move(b)]() mutable {
write_batch_sync(data);
});
}
for (auto& t : workers) {
if (t.joinable()) t.join();
}
}
}
static uint64_t get_dropped_logs() noexcept {
return instance().pool_.get_dropped_count();
}
~AsyncLogWriter() { if (initialized_) shutdown(); }
LogBlockPool pool_;
private:
AsyncLogWriter() = default;
void write_batch_sync(const std::vector<std::byte>& data) noexcept {
if (data.empty()) return;
if (use_fallback_) {
std::lock_guard<std::mutex> lk(fallback_mutex_);
fallback_.write(reinterpret_cast<const char*>(data.data()), data.size());
fallback_.flush();
} else {
DWORD written = 0;
::WriteFile(handle_, data.data(), static_cast<DWORD>(data.size()), &written, nullptr);
}
}
std::string filename_;
HANDLE handle_{ INVALID_HANDLE_VALUE };
std::ofstream fallback_;
std::mutex fallback_mutex_;
bool use_fallback_{ false };
bool initialized_{ false };
std::mutex init_mutex_;
Mode mode_{ Mode::Async };
};
inline size_t build_log_block_into(LogBlockPool::Block* block,
uint8_t level,
uint64_t status,
const std::vector<CallEntry>& call_stack,
std::string_view message,
LogEntryConverter* encryptor = nullptr) noexcept {
if (!encryptor) encryptor = global_encryptor().load();
uint8_t* dest = reinterpret_cast<uint8_t*>(block->data.data());
size_t callstack_section = sizeof(uint16_t) + call_stack.size() * (sizeof(uint32_t) + sizeof(uint16_t) + sizeof(float));
size_t message_section = sizeof(uint16_t) + message.size();
size_t payload_size = sizeof(LogEntryHeader) + callstack_section + message_section;
size_t total_size = sizeof(uint64_t) + sizeof(uint64_t) + payload_size;
*reinterpret_cast<uint64_t*>(dest) = BLOCK_SIGNATURE;
*reinterpret_cast<uint64_t*>(dest + 8) = total_size;
uint8_t* payload_start = dest + 16;
size_t offset = 0;
auto append = [&](const void* src, size_t sz) {
memcpy(payload_start + offset, src, sz);
offset += sz;
};
LogEntryHeader header{};
header.signature = BLOCK_SIGNATURE;
header.version = 1;
header.level = level;
header.status = status;
header.thread_id = ::GetCurrentThreadId();
header.timestamp_us = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
header.callstack_count = static_cast<uint16_t>(call_stack.size());
header.message_len = static_cast<uint16_t>(message.size());
append(&header, sizeof(header));
uint16_t count = header.callstack_count;
append(&count, sizeof(count));
for (const auto& e : call_stack) {
append(&e.func_id, sizeof(e.func_id));
append(&e.step, sizeof(e.step));
float measureTime = e.measure ? static_cast<float>(e.timing.avg_us) : 0.0f;
append(&measureTime, sizeof(measureTime));
}
uint16_t msg_len = header.message_len;
append(&msg_len, sizeof(msg_len));
if (msg_len > 0) {
append(message.data(), message.size());
}
if (encryptor) {
encryptor->convert(payload_start, payload_size);
}
return total_size;
}
inline void initialize(const std::string& filename = "app_trace.bin") noexcept {
AsyncLogWriter::instance().initialize(filename);
}
inline void shutdown() noexcept {
AsyncLogWriter::instance().shutdown();
}
inline void set_log_mode(bool synchronous) noexcept {
AsyncLogWriter::instance().set_mode(synchronous ? AsyncLogWriter::Mode::Sync : AsyncLogWriter::Mode::Async);
}
inline void flush_logs() noexcept {
AsyncLogWriter::instance().flush();
}
inline uint64_t get_dropped_logs() noexcept {
return AsyncLogWriter::get_dropped_logs();
}
inline void push(uint32_t func_id, bool measure = false) noexcept {
ThreadContextManager::get()->push(func_id, measure);
}
inline void pop() noexcept {
ThreadContextManager::get()->pop();
}
inline void step(uint16_t s) noexcept {
ThreadContextManager::get()->set_step(s);
}
template<typename... Args>
inline void log(uint8_t level, uint64_t status, const char* fmt, Args&&... args) noexcept {
auto& writer = AsyncLogWriter::instance();
auto* block = writer.pool_.try_claim();
if (!block) return;
thread_local std::string dynamic_buffer;
dynamic_buffer.clear();
char small_buffer[4096];
int len = _snprintf_s(small_buffer, sizeof(small_buffer), _TRUNCATE, fmt, std::forward<Args>(args)...);
std::string_view msg;
if (len >= 0 && static_cast<size_t>(len) < sizeof(small_buffer)) {
msg = { small_buffer, static_cast<size_t>(len) };
} else {
va_list ap;
va_start(ap, fmt);
int full_len = vsnprintf(nullptr, 0, fmt, ap);
va_end(ap);
if (full_len > 0 && full_len <= static_cast<int>(MAX_MESSAGE_LEN)) {
dynamic_buffer.resize(full_len);
va_start(ap, fmt);
vsnprintf(dynamic_buffer.data(), full_len + 1, fmt, ap);
va_end(ap);
msg = dynamic_buffer;
} else {
msg = "<message too long or error>";
}
}
auto* ctx = ThreadContextManager::get();
build_log_block_into(block, level, status, ctx->get_stack(), msg);
writer.pool_.commit(block);
if (writer.get_mode() == AsyncLogWriter::Mode::Sync) {
writer.flush();
}
}
inline void dump_all_thread_stacks() noexcept {
auto& tr = ThreadRegistry::instance();
auto main_tid = tr.main_tid();
auto active = tr.get_active();
std::string msg = "[DUMP ALL THREADS]\n";
msg += " Main: " + std::to_string(main_tid) + "\n";
msg += " Active: " + std::to_string(active.size()) + "\n";
for (const auto& [tid, ctx] : active) {
msg += " - [" + std::to_string(tid) + "] ";
const auto& stack = ctx->get_stack();
for (size_t i = 0; i < stack.size(); ++i) {
if (i > 0) msg += " -> ";
msg += "Function(" + std::to_string(stack[i].func_id) + "), Step(" + std::to_string(stack[i].step) + "), Measure(" + std::to_string(stack[i].measure ? static_cast<float>(stack[i].timing.avg_us) : 0.0f) + ")";
}
if (stack.empty()) msg += " <empty>";
msg += "\n";
}
printf("%s\n", msg.c_str());
log(255, 0xDEADC0DEULL, "%s", msg.c_str());
}
inline uint64_t& main_tid() noexcept {
return ThreadRegistry::instance().main_tid();
}
class [[nodiscard]] TraceScope {
public:
explicit TraceScope(uint32_t func_id, bool measure = false) noexcept
: func_id_(func_id), measure_(measure) {
push(func_id_, measure);
}
template<size_t N>
explicit TraceScope(const char(&name)[N], bool measure = false) noexcept
: TraceScope(static_hash(name), measure) {}
~TraceScope() noexcept { pop(); }
TraceScope(const TraceScope&) = delete;
TraceScope& operator=(const TraceScope&) = delete;
private:
uint32_t func_id_;
bool measure_;
static constexpr uint64_t fnv1a64(const char* s, uint64_t h = 14695981039346656037ULL) noexcept {
return *s ? fnv1a64(s + 1, (h ^ static_cast<uint64_t>(*s)) * 1099511628211ULL) : h;
}
static constexpr uint32_t static_hash(const char* s) noexcept {
return static_cast<uint32_t>(fnv1a64(s));
}
};
} // namespace tl
#define TRACE_LOG_ENABLED 1
#if TRACE_LOG_ENABLED
#define TL_SCOPE() tl::TraceScope __scope(__FUNCTION__)
#define TL_SCOPE_MEASURE() tl::TraceScope __scope(__FUNCTION__, true)
#define TL_SCOPE_ID(id) tl::TraceScope __scope(id)
#define TL_SCOPE_MEASURE_ID(id) tl::TraceScope __scope(id, true)
#define TL_STEP(s) tl::step(s)
#define TL_LOG(lvl, stat, ...) tl::log(lvl, stat, __VA_ARGS__)
#define TL_INIT(file) tl::initialize(file)
#define TL_SHUTDOWN() tl::shutdown()
#define TL_FLUSH() tl::flush_logs()
#define TL_SET_SYNC_MODE(on) tl::set_log_mode(on) // true = Sync, false = Async
#define TL_GET_DROPPED_LOGS() tl::get_dropped_logs()
#define TL_DUMP_TRACE_STACKS() tl::dump_all_thread_stacks()
#define TL_MAIN_TID() tl::main_tid()
#else
#define TL_SCOPE() do {} while(0)
#define TL_SCOPE_MEASURE() do {} while(0)
#define TL_SCOPE_ID(id) do {} while(0)
#define TL_SCOPE_MEASURE_ID(id) do {} while(0)
#define TL_STEP(s) do {} while(0)
#define TL_LOG(lvl, stat, ...) do {} while(0)
#define TL_INIT(file) do {} while(0)
#define TL_SHUTDOWN() do {} while(0)
#define TL_FLUSH() do {} while(0)
#define TL_SET_SYNC_MODE(on) do {} while(0)
#define TL_GET_DROPPED_LOGS() 0ULL
#define TL_DUMP_TRACE_STACKS() do {} while(0)
#define TL_MAIN_TID() 0ULL
#endif
import struct
import sys
from datetime import datetime, timedelta
from typing import Optional, List, Tuple
BLOCK_SIGNATURE = 0x544C4F47524F4B58 # "TLOGROKX"
MAX_MESSAGE_LEN = 8192
MAX_CALLSTACK_DEPTH = 256
ENCRYPTION_KEY = bytes([
0xac, 0x0a, 0xb0, 0xeb, 0x54, 0xee, 0x88, 0xe4,
0xea, 0x13, 0x89, 0x3a, 0xc1, 0x29, 0x0f, 0x24,
0x02, 0x15, 0xcf, 0x71, 0xab, 0x51, 0x3b, 0xda,
0x11, 0xde, 0x0f, 0xb1, 0xcd, 0xa9, 0xe4, 0x70
])
ENCRYPTION_NONCE = bytes([
0x75, 0xa3, 0xed, 0x51, 0x79, 0x84, 0xc7, 0xfa,
0x4b, 0x9e, 0xb7, 0xc2
])
LOG_LEVELS = {
0: "TRACE",
1: "DEBUG",
2: "INFO",
3: "WARN",
4: "ERROR",
5: "FATAL",
255: "DUMP"
}
def rotl(x: int, b: int) -> int:
return ((x << b) & 0xFFFFFFFF) | (x >> (32 - b))
def quarter_round(a, b, c, d):
a = (a + b) & 0xFFFFFFFF; d = rotl(d ^ a, 16)
c = (c + d) & 0xFFFFFFFF; b = rotl(b ^ c, 12)
a = (a + b) & 0xFFFFFFFF; d = rotl(d ^ a, 8)
c = (c + d) & 0xFFFFFFFF; b = rotl(b ^ c, 7)
return a, b, c, d
def chacha20_block(state: List[int]) -> bytes:
x = state[:]
for _ in range(10): # 20 rounds
# Column rounds
x[0], x[4], x[8], x[12] = quarter_round(x[0], x[4], x[8], x[12])
x[1], x[5], x[9], x[13] = quarter_round(x[1], x[5], x[9], x[13])
x[2], x[6], x[10], x[14] = quarter_round(x[2], x[6], x[10], x[14])
x[3], x[7], x[11], x[15] = quarter_round(x[3], x[7], x[11], x[15])
# Diagonal rounds
x[0], x[5], x[10], x[15] = quarter_round(x[0], x[5], x[10], x[15])
x[1], x[6], x[11], x[12] = quarter_round(x[1], x[6], x[11], x[12])
x[2], x[7], x[8], x[13] = quarter_round(x[2], x[7], x[8], x[13])
x[3], x[4], x[9], x[14] = quarter_round(x[3], x[4], x[9], x[14])
for i in range(16):
x[i] = (x[i] + state[i]) & 0xFFFFFFFF
keystream = bytearray()
for word in x:
keystream.extend(struct.pack("<I", word))
return bytes(keystream)
def chacha20_decrypt(data: bytes) -> bytes:
if len(data) == 0:
return data
state = [0] * 16
sigma = [0x61707865, 0x3320646e, 0x79622d32, 0x6b206574]
state[0:4] = sigma
# Key
for i in range(8):
state[4 + i] = struct.unpack("<I", ENCRYPTION_KEY[i*4:(i+1)*4])[0]
# Counter = 0
state[12] = 0
# Nonce
state[13] = struct.unpack("<I", ENCRYPTION_NONCE[0:4])[0]
state[14] = struct.unpack("<I", ENCRYPTION_NONCE[4:8])[0]
state[15] = struct.unpack("<I", ENCRYPTION_NONCE[8:12])[0]
decrypted = bytearray()
pos = 0
counter = 0
while pos < len(data):
block_state = state[:]
block_state[12] = counter & 0xFFFFFFFF
keystream = chacha20_block(block_state)
block_size = min(64, len(data) - pos)
for i in range(block_size):
decrypted.append(data[pos + i] ^ keystream[i])
pos += block_size
counter += 1
return bytes(decrypted)
class LogEntryParser:
def __init__(self, filename: str, decrypt: bool = True):
self.filename = filename
self.decrypt = decrypt
def parse(self):
with open(self.filename, "rb") as f:
data = f.read()
pos = 0
entry_count = 0
error_count = 0
print(f"Parsing log file: {self.filename}")
print(f"File size: {len(data)} bytes\n")
while pos + 16 <= len(data):
signature = struct.unpack_from("<Q", data, pos)[0]
if signature != BLOCK_SIGNATURE:
next_sig = data.find(struct.pack("<Q", BLOCK_SIGNATURE), pos + 1)
if next_sig == -1:
print("No more valid blocks found.")
break
print(f"[!] Invalid block at 0x{pos:X}, skipping to next signature at 0x{next_sig:X}")
pos = next_sig
continue
total_size = struct.unpack_from("<Q", data, pos + 8)[0]
if pos + total_size > len(data):
print(f"Incomplete block at 0x{pos:X} (declared size {total_size}), stopping.")
break
block_data = data[pos + 16 : pos + total_size]
try:
self.print_entry(block_data, entry_count, self.decrypt)
entry_count += 1
except Exception as e:
print(f"[ERROR] Failed to parse block at 0x{pos:X}: {e}")
error_count += 1
pos += total_size
print(f"\n=== Summary ===")
print(f"Total entries parsed: {entry_count}")
print(f"Errors: {error_count}")
def print_entry(self, payload: bytes, index: int, decrypt: bool):
if decrypt:
payload = chacha20_decrypt(payload)
offset = 0
# LogEntryHeader
header_fmt = "<Q B B Q I q H H"
header_size = struct.calcsize(header_fmt)
signature, version, level, status, thread_id, timestamp_us, callstack_count, message_len = \
struct.unpack_from(header_fmt, payload, offset)
offset += header_size
# Callstack section
callstack_count2 = struct.unpack_from("<H", payload, offset)[0]
offset += 2
callstack = []
for _ in range(callstack_count):
func_id = struct.unpack_from("<I", payload, offset)[0]
offset += 4
step = struct.unpack_from("<H", payload, offset)[0]
offset += 2
measure = struct.unpack_from("<f", payload, offset)[0]
offset += 4
callstack.append((func_id, step, measure))
# Message section
message_len2 = struct.unpack_from("<H", payload, offset)[0]
offset += 2
message_bytes = payload[offset : offset + message_len]
message = message_bytes.decode('utf-8', errors='replace')
# Timestamp
dt = datetime(1970, 1, 1) + timedelta(seconds=timestamp_us)
level_name = LOG_LEVELS.get(level, f"LEVEL_{level}")
print(f"[{index:04d}] {dt.strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]} "
f"| T:{thread_id} | {level_name} | Status:0x{status:016X}")
if callstack:
stack_str = " -> ".join(f"Function({func_id}), Step({step}), Measure({measure})" for func_id, step, measure in callstack)
print(f" Callstack: {stack_str}")
print(f" Message: {message}")
print("-" * 80)
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: python log_viewer.py <log_file.bin> [no_decrypt]")
sys.exit(1)
filename = sys.argv[1]
decrypt = "no_decrypt" not in sys.argv
parser = LogEntryParser(filename, decrypt=decrypt)
parser.parse()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment