diff --git a/hyperdbg/CMakeLists.txt b/hyperdbg/CMakeLists.txt index ba5b3855..389ba4e4 100644 --- a/hyperdbg/CMakeLists.txt +++ b/hyperdbg/CMakeLists.txt @@ -75,7 +75,7 @@ add_subdirectory(script-engine) link_directories(libraries/zydis/user libraries/keystone/release-lib) add_subdirectory(libhyperdbg) find_package(Threads REQUIRED) -target_link_libraries(libhyperdbg Zycore Zydis script-engine keystone Threads::Threads) +target_link_libraries(libhyperdbg Zycore Zydis script-engine keystone Threads::Threads ${CMAKE_DL_LIBS}) add_subdirectory(hyperdbg-cli) target_link_libraries(hyperdbg-cli libhyperdbg) diff --git a/hyperdbg/include/platform/general/header/Environment.h b/hyperdbg/include/platform/general/header/Environment.h index 82c3c7fa..237ce6f9 100644 --- a/hyperdbg/include/platform/general/header/Environment.h +++ b/hyperdbg/include/platform/general/header/Environment.h @@ -50,6 +50,10 @@ // POSIX sleep primitives (usleep) backing the Win32 Sleep() shim below # include +// DECIMAL_DIG and the FLT/DBL limits (ISO C99 ); MSVC exposes these +// transitively through its CRT/pch, glibc needs the explicit include +# include + // Windows string/char types typedef char TCHAR; typedef char * LPTSTR; diff --git a/hyperdbg/include/platform/general/header/nt-list.h b/hyperdbg/include/platform/general/header/nt-list.h index 0dc4dd2b..a62a2c34 100644 --- a/hyperdbg/include/platform/general/header/nt-list.h +++ b/hyperdbg/include/platform/general/header/nt-list.h @@ -1,6 +1,6 @@ /** * @file nt-list.h - * @author Max Raulea (max.raulea@gmail.com) + * @author Max Raulea (max.raulea@hyperdbg.org) * @brief Cross-platform NT-style intrusive doubly-linked list helpers + CONTAINING_RECORD * @details The shared debugger code uses the NT LIST_ENTRY API (InitializeListHead, * InsertHeadList, RemoveEntryList, CONTAINING_RECORD, ...). On Windows these diff --git a/hyperdbg/include/platform/user/code/platform-ioctl.c b/hyperdbg/include/platform/user/code/platform-ioctl.c index 086bff76..a1de6159 100644 --- a/hyperdbg/include/platform/user/code/platform-ioctl.c +++ b/hyperdbg/include/platform/user/code/platform-ioctl.c @@ -1,6 +1,6 @@ /** * @file platform-ioctl.c - * @author Max Raulea (max.raulea@gmail.com) + * @author Max Raulea (max.raulea@hyperdbg.org) * @brief User mode cross-platform implementation of the local kernel-driver IOCTL transport * @details See platform-ioctl.h. The Windows branch forwards directly to Win32 * DeviceIoControl / CreateFileA. The Linux branch is currently stubbed and is diff --git a/hyperdbg/include/platform/user/code/platform-lib-calls.c b/hyperdbg/include/platform/user/code/platform-lib-calls.c index 53736733..617cf23b 100644 --- a/hyperdbg/include/platform/user/code/platform-lib-calls.c +++ b/hyperdbg/include/platform/user/code/platform-lib-calls.c @@ -1,6 +1,6 @@ /** * @file platform-lib-calls.c - * @author Max Raulea (max.raulea@gmail.com) + * @author Max Raulea (max.raulea@hyperdbg.org) * @brief User mode Cross platform APIs for platofrm dependend library calls * @details * @version 0.19 @@ -21,6 +21,7 @@ # include # include # include +# include #endif // defined(__linux__) /** @@ -643,6 +644,46 @@ PlatformOpenFileForWriting(const WCHAR * Path) #endif } +/** + * @brief Platform independent wrapper to open a file for writing with + * OPEN_ALWAYS semantics (open existing without truncating, else create), + * taking a narrow (char*) path + * + * @details Unlike PlatformOpenFileForWriting (wide path, CREATE_ALWAYS/truncate) + * this keeps any existing file content. The Linux handle is a FILE* so + * it works with PlatformWriteFile / PlatformCloseFile. + * + * @param Path narrow path of the file to open or create + * @return HANDLE to the opened file, or INVALID_HANDLE_VALUE on failure + */ +HANDLE +PlatformOpenFileForWritingNarrow(const CHAR * Path) +{ +#if defined(_WIN32) + return CreateFileA(Path, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); +#elif defined(__linux__) + // + // NOT YET TESTED!! + // "r+b" opens an existing file at offset 0 without truncating (matching + // OPEN_ALWAYS on an existing file); if it does not exist, create it with + // "w+b". Return the FILE* as the HANDLE (PlatformWriteFile/PlatformCloseFile + // treat the Linux handle as a FILE*). + // + FILE * File = fopen(Path, "r+b"); + if (File == NULL) + { + File = fopen(Path, "w+b"); + } + if (File == NULL) + { + return INVALID_HANDLE_VALUE; + } + return (HANDLE)File; +#else +# error "Unsupported platform" +#endif +} + /** * @brief Platform independent wrapper to write a buffer to an open file * @@ -990,3 +1031,65 @@ PlatformGetExitCodeProcess(HANDLE Process, LPDWORD ExitCode) # error "Unsupported platform" #endif } + +/** + * @brief Platform independent wrapper for LoadLibrary + * + * @param ModulePath narrow path of the shared module to load + * @return HMODULE handle to the loaded module, or NULL on failure + */ +HMODULE +PlatformLoadLibrary(const CHAR * ModulePath) +{ +#if defined(_WIN32) + return LoadLibraryA(ModulePath); +#elif defined(__linux__) + // NOT YET TESTED!! + return (HMODULE)dlopen(ModulePath, RTLD_NOW | RTLD_LOCAL); +#else +# error "Unsupported platform" +#endif +} + +/** + * @brief Platform independent wrapper for GetProcAddress + * + * @param Module module handle returned by PlatformLoadLibrary + * @param ProcName name of the exported symbol to resolve + * @return PVOID address of the symbol, or NULL if not found + */ +PVOID +PlatformGetProcAddress(HMODULE Module, const CHAR * ProcName) +{ +#if defined(_WIN32) + return (PVOID)GetProcAddress(Module, ProcName); +#elif defined(__linux__) + // NOT YET TESTED!! + return dlsym((void *)Module, ProcName); +#else +# error "Unsupported platform" +#endif +} + +/** + * @brief Platform independent wrapper for FreeLibrary + * + * @param Module module handle returned by PlatformLoadLibrary + * @return BOOL non-zero on success, zero on failure + */ +BOOL +PlatformFreeLibrary(HMODULE Module) +{ +#if defined(_WIN32) + return FreeLibrary(Module); +#elif defined(__linux__) + // + // NOT YET TESTED!! + // dlclose returns 0 on success (opposite of FreeLibrary), so invert it to + // preserve the "non-zero == success" contract. + // + return (BOOL)(dlclose((void *)Module) == 0); +#else +# error "Unsupported platform" +#endif +} diff --git a/hyperdbg/include/platform/user/code/platform-serial.c b/hyperdbg/include/platform/user/code/platform-serial.c index 6266c0a8..f1c01050 100644 --- a/hyperdbg/include/platform/user/code/platform-serial.c +++ b/hyperdbg/include/platform/user/code/platform-serial.c @@ -1,6 +1,6 @@ /** * @file platform-serial.c - * @author Max Raulea (max.raulea@gmail.com) + * @author Max Raulea (max.raulea@hyperdbg.org) * @brief User mode cross-platform implementation of the kernel-debugger serial transport * @details See platform-serial.h. The Windows branch wraps the Win32 serial primitives * (CreateFile / Comm* / overlapped ReadFile/WriteFile) and owns the per-direction diff --git a/hyperdbg/include/platform/user/code/platform-signal.c b/hyperdbg/include/platform/user/code/platform-signal.c index b0f83071..d6751b0f 100644 --- a/hyperdbg/include/platform/user/code/platform-signal.c +++ b/hyperdbg/include/platform/user/code/platform-signal.c @@ -1,6 +1,6 @@ /** * @file platform-signal.c - * @author Max Raulea (max.raulea@gmail.com) + * @author Max Raulea (max.raulea@hyperdbg.org) * @brief User mode cross-platform implementation of the console-control handler * @details See platform-signal.h. The Windows branch forwards to SetConsoleCtrlHandler. * The Linux branch blocks the handled signals and dispatches them from a diff --git a/hyperdbg/include/platform/user/header/platform-ioctl.h b/hyperdbg/include/platform/user/header/platform-ioctl.h index 203a7459..336d3811 100644 --- a/hyperdbg/include/platform/user/header/platform-ioctl.h +++ b/hyperdbg/include/platform/user/header/platform-ioctl.h @@ -1,6 +1,6 @@ /** * @file platform-ioctl.h - * @author Max Raulea (max.raulea@gmail.com) + * @author Max Raulea (max.raulea@hyperdbg.org) * @brief User mode cross-platform interface for the local kernel-driver IOCTL transport * @details Distinct from the serial transport (platform-serial), which talks to a remote * debuggee. This interface is the LOCAL control channel: the userspace library diff --git a/hyperdbg/include/platform/user/header/platform-lib-calls.h b/hyperdbg/include/platform/user/header/platform-lib-calls.h index d9451ad3..d5dcaf29 100644 --- a/hyperdbg/include/platform/user/header/platform-lib-calls.h +++ b/hyperdbg/include/platform/user/header/platform-lib-calls.h @@ -1,6 +1,6 @@ /** * @file platform-lib-calls.h - * @author Max Raulea (max.raulea@gmail.com) + * @author Max Raulea (max.raulea@hyperdbg.org) * @brief User mode Cross platform APIs for platofrm dependend library calls * @details * @version 0.19 @@ -157,6 +157,16 @@ PlatformWriteConsole(const VOID * Buffer, DWORD NumberOfBytes); HANDLE PlatformOpenFileForWriting(const WCHAR * Path); +// +// Narrow (char*) variant with OPEN_ALWAYS semantics (open existing, else +// create; no truncate), as opposed to the wide PlatformOpenFileForWriting above +// which truncates (CREATE_ALWAYS). Used by the event-forwarding file sink, whose +// path is already a narrow std::string, so it sidesteps the wide-char issue and +// works on Linux. +// +HANDLE +PlatformOpenFileForWritingNarrow(const CHAR * Path); + BOOLEAN PlatformWriteFile(HANDLE FileHandle, const VOID * Buffer, DWORD NumberOfBytes); @@ -228,3 +238,20 @@ PlatformResumeThread(HANDLE Thread); BOOL PlatformGetExitCodeProcess(HANDLE Process, LPDWORD ExitCode); + +// +// DYNAMIC LIBRARY LOADING +// +// Thin wrappers over LoadLibrary/GetProcAddress/FreeLibrary, used by the +// event-forwarding "module" sink (loads a plugin exporting +// hyperdbg_event_forwarding). Windows = the Win32 calls; Linux = dlopen/dlsym/ +// dlclose (exact 1:1 semantic map). +// +HMODULE +PlatformLoadLibrary(const CHAR * ModulePath); + +PVOID +PlatformGetProcAddress(HMODULE Module, const CHAR * ProcName); + +BOOL +PlatformFreeLibrary(HMODULE Module); diff --git a/hyperdbg/include/platform/user/header/platform-serial.h b/hyperdbg/include/platform/user/header/platform-serial.h index f33b48ec..40cf5756 100644 --- a/hyperdbg/include/platform/user/header/platform-serial.h +++ b/hyperdbg/include/platform/user/header/platform-serial.h @@ -1,6 +1,6 @@ /** * @file platform-serial.h - * @author Max Raulea (max.raulea@gmail.com) + * @author Max Raulea (max.raulea@hyperdbg.org) * @brief User mode cross-platform interface for the kernel-debugger serial transport * @details The kernel-debugging *protocol* in kd.cpp is platform independent; only * the byte transport underneath it (serial COM port / named pipe) is OS diff --git a/hyperdbg/include/platform/user/header/platform-signal.h b/hyperdbg/include/platform/user/header/platform-signal.h index 9a3f73db..635baad4 100644 --- a/hyperdbg/include/platform/user/header/platform-signal.h +++ b/hyperdbg/include/platform/user/header/platform-signal.h @@ -1,6 +1,6 @@ /** * @file platform-signal.h - * @author Max Raulea (max.raulea@gmail.com) + * @author Max Raulea (max.raulea@hyperdbg.org) * @brief User mode cross-platform interface for the console-control (CTRL+C / CTRL+BREAK) handler * @details HyperDbg installs a single handler (BreakController) that pauses the * debuggee when the user hits CTRL+C / CTRL+BREAK. The handler body is diff --git a/hyperdbg/libhyperdbg/CMakeLists.txt b/hyperdbg/libhyperdbg/CMakeLists.txt index 26bbc5ff..67096b76 100644 --- a/hyperdbg/libhyperdbg/CMakeLists.txt +++ b/hyperdbg/libhyperdbg/CMakeLists.txt @@ -193,6 +193,8 @@ if(UNIX) list(APPEND SourceFiles "code/debugger/user-level/pe-parser-linux.cpp") list(REMOVE_ITEM SourceFiles "code/debugger/driver-loader/install.cpp") list(APPEND SourceFiles "code/debugger/driver-loader/install-linux.cpp") + list(REMOVE_ITEM SourceFiles "code/debugger/communication/namedpipe.cpp") + list(APPEND SourceFiles "code/debugger/communication/namedpipe-linux.cpp") endif() add_library(libhyperdbg SHARED ${SourceFiles}) diff --git a/hyperdbg/libhyperdbg/code/debugger/communication/forwarding.cpp b/hyperdbg/libhyperdbg/code/debugger/communication/forwarding.cpp index b6d3d940..b147d2d8 100644 --- a/hyperdbg/libhyperdbg/code/debugger/communication/forwarding.cpp +++ b/hyperdbg/libhyperdbg/code/debugger/communication/forwarding.cpp @@ -142,7 +142,7 @@ ForwardingCloseOutputSource(PDEBUGGER_EVENT_FORWARDING SourceDescriptor) // // Close the handle // - CloseHandle(SourceDescriptor->Handle); + PlatformCloseFile(SourceDescriptor->Handle); // // Return the status @@ -183,7 +183,7 @@ ForwardingCloseOutputSource(PDEBUGGER_EVENT_FORWARDING SourceDescriptor) // // Free the library // - FreeLibrary(SourceDescriptor->Module); + PlatformFreeLibrary(SourceDescriptor->Module); // // Return the status @@ -226,7 +226,7 @@ ForwardingCreateOutputSource(DEBUGGER_EVENT_FORWARDING_TYPE SourceType, // // Create a new file // - HANDLE FileHandle = CreateFileA(Description.c_str(), GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + HANDLE FileHandle = PlatformOpenFileForWritingNarrow(Description.c_str()); // // The handle might be INVALID_HANDLE_VALUE which will be @@ -236,7 +236,7 @@ ForwardingCreateOutputSource(DEBUGGER_EVENT_FORWARDING_TYPE SourceType, } else if (SourceType == EVENT_FORWARDING_MODULE) { - HMODULE ModuleHandle = LoadLibraryA(Description.c_str()); + HMODULE ModuleHandle = PlatformLoadLibrary(Description.c_str()); if (ModuleHandle == NULL) { @@ -244,7 +244,7 @@ ForwardingCreateOutputSource(DEBUGGER_EVENT_FORWARDING_TYPE SourceType, return INVALID_HANDLE_VALUE; } - hyperdbg_event_forwarding_t hyperdbg_event_forwarding = (hyperdbg_event_forwarding_t)GetProcAddress(ModuleHandle, "hyperdbg_event_forwarding"); + hyperdbg_event_forwarding_t hyperdbg_event_forwarding = (hyperdbg_event_forwarding_t)PlatformGetProcAddress(ModuleHandle, "hyperdbg_event_forwarding"); if (hyperdbg_event_forwarding == NULL) { @@ -503,11 +503,9 @@ ForwardingWriteToFile(HANDLE FileHandle, CHAR * Message, UINT32 MessageLength) DWORD BytesWritten = 0; BOOL ErrorFlag = FALSE; - ErrorFlag = WriteFile(FileHandle, // open file handle - Message, // start of data to write - MessageLength, // number of bytes to write - &BytesWritten, // number of bytes that were written - NULL); // no overlapped structure + ErrorFlag = PlatformWriteFile(FileHandle, // open file handle + Message, // start of data to write + MessageLength); // number of bytes to write return TRUE; diff --git a/hyperdbg/libhyperdbg/code/debugger/driver-loader/install-linux.cpp b/hyperdbg/libhyperdbg/code/debugger/driver-loader/install-linux.cpp index cd6c4eab..d21a64df 100644 --- a/hyperdbg/libhyperdbg/code/debugger/driver-loader/install-linux.cpp +++ b/hyperdbg/libhyperdbg/code/debugger/driver-loader/install-linux.cpp @@ -1,6 +1,6 @@ /** * @file install-linux.cpp - * @author Max Raulea (max.raulea@gmail.com) + * @author Max Raulea (max.raulea@hyperdbg.org) * @brief Linux stub implementations of the driver-loader (install.cpp) * @details The Windows implementation (install.cpp) loads/unloads the HyperDbg * kernel-mode driver (the .sys file that contains the actual debugging diff --git a/hyperdbg/libhyperdbg/code/debugger/script-engine/symbol-linux.cpp b/hyperdbg/libhyperdbg/code/debugger/script-engine/symbol-linux.cpp index 2f7f65a4..6a8f558d 100644 --- a/hyperdbg/libhyperdbg/code/debugger/script-engine/symbol-linux.cpp +++ b/hyperdbg/libhyperdbg/code/debugger/script-engine/symbol-linux.cpp @@ -1,6 +1,6 @@ /** * @file symbol-linux.cpp - * @author Max Raulea (max.raulea@gmail.com) + * @author Max Raulea (max.raulea@hyperdbg.org) * @brief Linux stub implementations of the symbol subsystem * @details The Windows implementation uses DbgHelp + PDB files (symbol-parser/). * Linux uses ELF/DWARF which requires a separate implementation. diff --git a/hyperdbg/libhyperdbg/code/debugger/user-level/pe-parser-linux.cpp b/hyperdbg/libhyperdbg/code/debugger/user-level/pe-parser-linux.cpp index 6edaa478..9c56e32e 100644 --- a/hyperdbg/libhyperdbg/code/debugger/user-level/pe-parser-linux.cpp +++ b/hyperdbg/libhyperdbg/code/debugger/user-level/pe-parser-linux.cpp @@ -1,6 +1,6 @@ /** * @file pe-parser-linux.cpp - * @author Max Raulea (max.raulea@gmail.com) + * @author Max Raulea (max.raulea@hyperdbg.org) * @brief Linux stub implementations of the PE (Portable Executable) parser * @details The Windows implementation (pe-parser.cpp) parses the full PE image * format and depends on the complete set of Windows IMAGE_* headers, diff --git a/hyperdbg/linux/PORTING_STATUS.md b/hyperdbg/linux/PORTING_STATUS.md index f180542d..9a918723 100644 --- a/hyperdbg/linux/PORTING_STATUS.md +++ b/hyperdbg/linux/PORTING_STATUS.md @@ -77,9 +77,11 @@ Shared, OS-neutral headers: | `.../script-engine/symbol-linux.cpp` | `symbol.cpp` (DbgHelp + PDB) | All `Symbol*` functions. Only `SymbolConvertNameOrExprToAddress` does real work: parses a plain hex/decimal literal so numeric addresses work. | Real ELF/DWARF symbol parser (libdw / libelf / libbfd). | | `.../user-level/pe-parser-linux.cpp` | `pe-parser.cpp` (Windows PE format) | The 3 public fns: `PeShowSectionInformationAndDump`, `PeIsPE32BitOr64Bit` (→ FALSE), `PeGetSyscallNumber` (→ 0). | Recreate the Windows `IMAGE_*` headers for Linux, then port `pe-parser.cpp`. Only needed for Windows-target debugging on Linux. | | `.../driver-loader/install-linux.cpp` | `install.cpp` (SCM driver loader) | The 2 Linux-visible public fns: `ManageDriver` (→ FALSE) and `SetupPathForFileName` (→ FALSE). The 4 `SC_HANDLE` helpers (`InstallDriver`/`RemoveDriver`/`StartDriver`/`StopDriver`) are guarded out of `install.h` on Linux (never referenced there). | `ManageDriver`: load/unload a future HyperDbg Linux kernel module via `finit_module`/`delete_module` (needs CAP_SYS_MODULE). `SetupPathForFileName`: `readlink("/proc/self/exe")` + strip + append + `access()` (generic "find a file beside my binary"; also used by hwdbg). | +| `.../communication/namedpipe-linux.cpp` | `namedpipe.cpp` (Win32 named-pipe IPC) | All 10 public `NamedPipeServer*`/`NamedPipeClient*` fns. `Create*` → `INVALID_HANDLE_VALUE` (print); send/read → 0/FALSE; close → no-op (quiet, unreachable once Create fails). The two internal `*Example()` demos are not in the Linux TU. | Back with a filesystem FIFO (`mkfifo`) or, better for framed bidirectional messages, an `AF_UNIX` socket derived from the `\\.\pipe\NAME` string; overlapped/event I/O collapses to blocking `read`/`write`. | -All three self-guard with `#ifdef __linux__` and print -`"... is not supported on Linux yet"` at runtime. +All four self-guard with `#ifdef __linux__` and print +`"... is not supported on Linux yet"` at runtime (named-pipe: only in the +`Create*` entry points, to avoid per-loop spam). --- @@ -320,6 +322,55 @@ over serial/namedpipe). Two mechanical fixes: Matches the CTRL_*/PROCESS_*/ERROR_* constant blocks already there. Actual Linux serial I/O is still the platform-serial termios TODO. +### formats.cpp DECIMAL_DIG — DONE (2026-07-22) + +`meta-commands/formats.cpp:94` uses `DECIMAL_DIG` (the ISO C99 `` macro, +widest-float round-trip digit count) in a `.formats` output format string. MSVC +exposes it transitively via its CRT/pch; glibc needs the explicit include. +**Pure addition:** `#include ` in the `Environment.h` Linux block +(next to ``/``). Standard header, cross-platform-safe. + +### forwarding.cpp output-event forwarding — DONE (2026-07-22) + +`communication/forwarding.cpp` is the debug-output forwarding subsystem (sinks: +file / TCP / named-pipe / loadable module). Bucket-2, multi-category. User chose +**new Platform\* wrappers** for both non-trivial subsystems (not guards). + +- **Clean swap:** `WriteFile`→`PlatformWriteFile` (exact match; the original + assigns the result then unconditionally `return TRUE`, so the error-check below + was already dead code — `BytesWritten` out-param dropped, still referenced by + that dead code so no unused-var). `CloseHandle` (FILE source)→`PlatformCloseFile` + (fclose on Linux — matches the FILE\* the new open returns). +- **File sink** (`CreateFileA`, narrow path + `OPEN_ALWAYS`): existing + `PlatformOpenFileForWriting` did NOT fit (it is wide + `CREATE_ALWAYS`/truncate), + so **pure addition** `PlatformOpenFileForWritingNarrow(const CHAR *)` — Windows + `CreateFileA(...OPEN_ALWAYS...)`; Linux `fopen("r+b")` then `fopen("w+b")` + (open-existing-no-truncate, else create) returning the `FILE*` as the HANDLE. + Named `...Narrow` (user preference) to flag the char-width difference vs the + wide variant. Because the path is already a narrow `std::string`, this sink + actually works on Linux — no wide-char blocker. +- **Module/plugin sink** (`LoadLibraryA`/`GetProcAddress`/`FreeLibrary`): **pure + additions** `PlatformLoadLibrary`/`PlatformGetProcAddress`/`PlatformFreeLibrary` + in platform-lib-calls — Windows real; Linux `dlopen(RTLD_NOW|RTLD_LOCAL)`/ + `dlsym`/`dlclose` (dlclose return inverted to keep "non-zero == success"). + `PlatformGetProcAddress` returns `PVOID` (no `FARPROC` on Linux); caller casts. +- **Build:** added `#include ` to the platform-lib-calls Linux includes; + added `${CMAKE_DL_LIBS}` to the `libhyperdbg` link (top-level CMakeLists) — the + portable dl link (empty where dl is in libc). Only libhyperdbg compiles + platform-lib-calls.c on Linux, so no other target needed it. +- ⚠️ All four new Linux branches marked `NOT YET TESTED!!` in source. + +### namedpipe.cpp — DONE via namedpipe-linux.cpp + CMake swap (2026-07-22) + +`communication/namedpipe.cpp` is a whole Windows-only TU (Win32 named-pipe IPC: +server `CreateNamedPipe`/`ConnectNamedPipe`, client `CreateFileA` on `\\.\pipe\` ++ overlapped `ReadFile`/`WriteFile` via `g_OverlappedIoStructureFor*Debugger`). +Followed pattern-2 (like symbol/pe-parser/install): new `namedpipe-linux.cpp` +`#ifdef __linux__` stubs of the 10 public `NamedPipe{Server,Client}*` fns; +`namedpipe.cpp` left 100% untouched; CMake `if(UNIX)` REMOVE_ITEM + APPEND swap. +6 callers link the stubs transparently (forwarding/kd/debug/export/tests/test). +See the Linux-replacement-files table above for the FIFO/AF_UNIX TODO. + --- ## TODO ledger — revisit before Linux is functional