2026-04-27
Discoveries
Tools:
- Wireguard (For Windows) v1.0 - This is a recent thing.
- TUI SQLite Viewer
- Looks great and feels responsive.
- Has no "schema only" viewer. Always loads content.
- Has no horizontal slide bar, but using arrow keys work.
- Has no way to run SQL commands or
LIMITthe results returned.- Maybe the work around is to create Views? I'm not doing that for a SQL browser.
- Online Photo Editor - Photoshop like stuff in browser.
Dev:
- (Small) Planet Walking In Godot - Gist: Center point of gravity. Use Areas for gravity effect (allowing jumping between fields). Re-adjust player Up Normal in physics process.
Articles:
- Databases Were Not Designed for This - Gist: Databases were built for humans that try, not LLM coders that don't.
- Has The LHC Destroyed The World Yet? - I can confirm the accuracy of this site.
Resources:
- Anna's Archive - Free EBook Repository
- Free Media, Heck Yeah! (FMHY) - Free stuff on the internet.
- removepaywall.com - Avoid paywalls by finding archived alternatives.
- CamelCamelCamel - Check historical pricing of a thing.
- WhereToWatch - Find services streaming a specific title.
- Online Etymology Dictionary
- Windy Weather - Eye candy weather service.
- Gatwy - Browser based RDP/SSH/SMB/VNC ("Guacamole Alternative") github #susLLM
- kdenlive - Free Video Editor
- AlterSend - Send files between devices (i.e. peer to peer), no cloud.
- lnav - Log File Viewer
- flameshot - Screenshot Software
- yt-dlp - Video Downloader
Rust Things
I enjoy minimal binaries. Rust promises me a delightful development experience once I graduate to "rust developer". As a old embedded C-developer, I've only decided Rust is worth looking at because I can reduce its existance to a single object file (*.o) to be linked into whatever scheme my heart desires. At the moment, I'm attempting to thread the needle between several domains including C, C++, and Python, to find my happy place in Rust.
First things first, in any "minimal" Rust library, std is the first thing to pitch. No thank you! Secondly, I don't need whatever wrapper or initializations stuff Rust wants to preempt my code with. We'll stick with the classic C main() function. Note: Its understood that the real entry point is likely _start and its expected that is where the stack and register initialization will occur.
#![no_std]
#![no_main]
#[no_mangle]
pub extern "C" fn main(_argc: i32, _argv: *const *const u8) -> ! {
// ... spicy rust code here ...
}
Second thing, a sophisticated panic handler could be nice for end users and troubleshooting. But in the end, its a panic. I'm not here to engineer panics, I'm here to engineer avoiding panics. I don't want panic bloating my minimal setups. (Not to mention, a low level panic usually becomes a soft reboot or a watchdog reboot!).
use core::panic::PanicInfo;
#[panic_handler]
fn panic(_: &PanicInfo) -> ! {
unsafe {
libc::write(2, b"panic\n".as_ptr() as *const libc::c_void, 6);
libc::exit(1);
}
}
#[no_mangle]
pub extern "C" fn rust_eh_personality() {
// Called by debug libcore during exception handling.
}
Last thing we nearly always need is an allocator. I don't know what Rust uses under the hood. All I know is that the world of POSIX computing has operated to my satisfaction with libc and its malloc/realloc/free calls. So we'll keep that the standard!
use core::alloc::{GlobalAlloc, Layout};
pub struct LibcAllocator;
unsafe impl GlobalAlloc for LibcAllocator {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
libc::malloc(layout.size()) as *mut u8
}
unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
libc::free(ptr as *mut libc::c_void)
}
unsafe fn realloc(&self, ptr: *mut u8, _layout: Layout, new_size: usize) -> *mut u8 {
libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8
}
}
#[global_allocator]
pub static ALLOCATOR: LibcAllocator = LibcAllocator;
Ok, we're looking good. Lets set up cargo to do the correct thing with the toolchain. Essentially, compile for size, use link time optimization, and strip symbols. For developer builds, we explicitly include symbols for better rust-lldb/CodeLLDB experience.
[package]
name = "myapp"
version = "0.1.0"
edition = "2021"
[dependencies]
libc = { version = "0.2", default-features = false }
[profile.release]
opt-level = "z"
lto = true
codegen-units = 1
panic = "abort"
strip = true
[profile.dev]
panic = "abort"
debug = true
With libc crate, a panic handler, and an allocator defined, we get access to nearly everything in the system's libc and rust's core and rust's alloc namespaces. This includes file IO, syscalls, formatting, lists, and maps. In nearly everything that I've ever done in embedded development and CLI development, this is all you ever actually require.
Rust is currently not capable of handling variadic function calls or valist parameters in stable Rust. Therefore we can't use the printf, directly. Since we trashed std, we also trashed println!. Here is a rewrite of println! macro using what we've left ourselves. (Note: cstdlib is a wrapper around libc calls to hide away unavoidable unsafe sections.) It leans completely on the formatting provided in the core::fmt::Write trait. The below implementation targets STDOUT, but as you'll see, you can easily target any file descriptor.
use crate::cstdlib::{write, STDOUT};
use core::fmt::{self, Write};
struct Stdout;
impl Write for Stdout {
fn write_str(&mut self, s: &str) -> fmt::Result {
write(STDOUT, s.as_bytes());
Ok(())
}
}
pub fn _print(args: fmt::Arguments) {
use core::fmt::Write;
Stdout.write_fmt(args).unwrap();
}
#[macro_export]
macro_rules! print {
($($arg:tt)*) => ({
$crate::print::_print(core::format_args!($($arg)*));
});
}
#[macro_export]
macro_rules! println {
() => ($crate::print!("\n"));
($fmt:expr) => (
$crate::print!(concat!($fmt, "\n"))
);
($fmt:expr, $($arg:tt)*) => (
$crate::print!(
concat!($fmt, "\n"),
$($arg)*
)
);
}
Here is a snippet of cstdlib.rs:
pub const STDOUT: i32 = 1;
pub const SIGTRAP: i32 = libc::SIGTRAP;
pub fn exit(code: i32) -> ! {
unsafe { libc::exit(code); }
}
pub fn write(fd: i32, buf: &[u8]) -> isize {
unsafe { libc::write(fd, buf.as_ptr() as *const libc::c_void, buf.len()) }
}
pub fn abort() -> ! {
unsafe { libc::abort(); }
}
pub fn raise(sig: i32) -> i32 {
unsafe { libc::raise(sig) }
}
Something I've found necessary for effective development (regardless of language) is an explicit breakpoint that I can embed in my code. I hate having to set breakpoints in debuggers when I know where in the code I must start inspection. I want the debugger to run and stop based on the code! Therefore I've also included a breakpoint! macro in my minimal environment. (Note: It has a SIGTRAP catch all for architectures I haven't planned for. The SIGTRAP does require jumping out of extra contexts because its implemented via pthread and you need to exist the pthread call stack.)
#[macro_export]
macro_rules! breakpoint {
() => {
#[cfg(debug_assertions)]
unsafe {
// x86 / x86_64
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
core::arch::asm!("int3", options(nomem, nostack, preserves_flags));
// ARM64
#[cfg(target_arch = "aarch64")]
core::arch::asm!("brk #0", options(nomem, nostack, preserves_flags));
// ARM32
#[cfg(target_arch = "arm")]
core::arch::asm!("bkpt #0", options(nomem, nostack, preserves_flags));
// MIPS
#[cfg(any(target_arch = "mips", target_arch = "mips64"))]
core::arch::asm!("break", options(nomem, nostack, preserves_flags));
// AVR
#[cfg(target_arch = "avr")]
core::arch::asm!("break", options(nomem, nostack, preserves_flags));
// RISC-V
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
core::arch::asm!("ebreak", options(nomem, nostack, preserves_flags));
// WASM
#[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
core::arch::asm!("unreachable", options(nomem, nostack, preserves_flags));
// PowerPC
#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
core::arch::asm!("tw 31,0,0", options(nomem, nostack));
// Sparc
#[cfg(any(target_arch = "sparc", target_arch = "sparc64"))]
core::arch::asm!("ta 1", options(nomem, nostack));
// S390X
#[cfg(target_arch = "s390x")]
core::arch::asm!("trap2");
// LoongArch64
#[cfg(target_arch = "loongarch64")]
core::arch::asm!("break 0", options(nomem, nostack, preserves_flags));
#[cfg(target_arch="hexagon")]
core::arch::asm!("trap0(#0)", options(nomem, nostack));
#[cfg(target_arch="m68k")]
core::arch::asm!("trap #15", options(nomem, nostack));
#[cfg(target_arch="csky")]
core::arch::asm!("bkpt", options(nomem, nostack, preserves_flags));
#[cfg(target_arch="xtensa")]
core::arch::asm!("break 0,0", options(nomem, nostack, preserves_flags));
// Catch-all
#[cfg(not(any(
target_arch = "x86",
target_arch = "x86_64", // Only one I've tested.
target_arch = "aarch64",
target_arch = "arm",
target_arch = "mips",
target_arch = "mips64",
target_arch = "avr",
target_arch = "riscv32",
target_arch = "riscv64",
target_arch = "wasm32",
target_arch = "wasm64",
target_arch = "powerpc",
target_arch = "powerpc64",
target_arch = "sparc",
target_arch = "sparc64",
target_arch = "s390x",
target_arch = "loongarch64",
target_arch = "hexagon",
target_arch = "m68k",
target_arch = "csky",
target_arch = "xtensa",
)))]
{
// Note: bpf and nvptx64 have no breakpoint.
::libc::raise(::libc::SIGTRAP);
//compile_error!("No breakpoint instruction defined for this architecture");
}
}
}
}
Right, so presuming you've organized the relevant snippets above into corresponding files: allocator.rs, panic.rs, print.rs, debug.rs, you can now have a main.rs that resembles:
#[no_mangle]
pub extern "C" fn main(_argc: i32, _argv: *const *const u8) -> ! {
let mystr: &str = "sup";
write(STDOUT, b"hello\n");
breakpoint!();
println!("Mine: {}", mystr);
exit(0);
}
Running cargo build && rust-lldb target/debug/myapp then run in lldb will net you a halted app where you can step the remainder of the code, inspect the application (e.g. frame variable) and accomplish all your goals and dreams.