bugs:
u128 <bad size>
gets stuck when debuggee is OOM-killed by linux
investigate why many types are not deduped, e.g. there's DB::Block#441
make stack unwinding work when control is in .plt or .plt.got, see "Recognise PLT entries such as" in libunwind code
fix incorrect column numbers with tab indentation (tabs should be counted as 1 column, but we turn them into multiple spaces)
fix line-wrapped copy-paste (seems to copy only the first line of selection) and line-wrapped C-k (deletes only to the end of post-wrapping line, should use pre-wrapping line)
make auto-downcast check that the types are in the same language, to avoid downcasting C++ type to Rust type with same name (e.g. "parquet::format::PageHeader"); check if type decl/def matching has the same problem

performance:
optimize symbols loading
  more dynamic work distribution to threads (see util% in --load-symbols output on devserver)
    dynamically assign units to shards?
      fixup_subfunction_call_line
      worse locality
      go by units (unit groups?) instead of by data kind
    per-unit sort+dedup (then no dedup across units)
    piecewise sort
    dynamically pick dfs roots
    small buckets for shuffles in types
  memory usage
    separate allocator for temp memory to make sure it's released to OS after symbols loading
  madvise
    benchmark with file pre-evicted from page cache (using vmtouch)
  fix warning about unsupported forms, especially implicit_const on flags
  try caching chase results (71M chases, 15M unique results, 205M total DIEs)
  test with dwarf 4
  simple things found by profiler (samply is nice)
look at profiler on ch server (1500 threads)
test with 10k threads
  fix O(n^2) stuff until syscalls are the slowest part
  time waitpid separately
  waitpid is suspiciously slow; does it iterate over threads? can partially avoid it by anticipating which threads will get events?
  if there are enough free hw breakpoints, activate new breakpoints as hw and thread-specific right away without waiting for them to be spuriously hit by other threads
  maybe avoid duplicate POKEUSER calls for debug registers if the thread already had them assigned
test with watches window filled with long arrays (I saw 50ms frames when there are ~5 of them; maybe just decrease length limit)
investigate unresponsive ui when conditional breakpoint is hit at a high rate

todo:
avoid flickering when typing in dialogs, somehow
in type search, dedup builtin types so that they're not listed once for each binary
tooltip in status window with more log lines and more space for last error
try with odin
zig pretty-printers
support gnu_debugaltlink, as found in zsh in debuginfod
output window (plain text)
get debuglink binaries from debuginfod
reverse --tty mode: run debugger in another window and the debuggee in current window
"Expected an attribute value to be a string form" on zsh
buffer input when program is quitting, especially k+r and steps
test with breakpad minidumps
modifying debuggee variables (memory and registers), modifying ip
log a message if the process forked away; do something about software breakpoints being inherited on fork and crashing the unattached child when hit
add alternative default key binds for next/prev search result, F3 is not always available on mac
async fetch from debuginfod (load symbols without waiting for it, then on success start over)
show an error if program failed to start (e.g. executable doesn't exist)
panic screen: show stack trace and process state, type something to resume+detach or kill or email stack trace or quit
allow specifying cgroup and user (or maybe it's too hard, need to maybe inherit groups from parent somehow too)
maybe refresh global variables in watches window on periodic timer tick when the program is running
make watch window show dereferenced string-like values by default (otherwise expanding it shows the array of characters and eats all vertical space)
update rust HashMap pretty printer
detect and show if a pointer points to a symbol (function, global variable, vtable)
do something for downcasts in conditional breakpoints (coalesce()? maybe()? ?()? ()?? checkbox to stop on error? 'is' operator? explicit checked downcast? also function to check field presense without evaluating it)
`in` operator, e.g. x in [1, 2, 3]
make names in MetaType etc unexpandable as array
make '^' apply to expressions instead of variable names, e.g. ^(this.query_context)
allow adding unconditional breakpoint on the same line as conditional one, somehow
global variables from .symtab, maybe from .debug_pubnames (maybe also look into .debug_pubtypes)
more built-in pretty printers: boost::multi_index sparsehash, absl, rust b-trees
hotkey to switch between .h/.cpp (/.cc/.hh/.hpp/.cxx - maybe just anything after '.')
maximizing windows
meta functions like checking for field presence of superclass type for use in conditions
key to freeze value in watches window; can also be used for controlling when to run the expression if it has side effects
allow expressions (especially conditions) to have multiple statements separated by ';'
"unexpectedly big memory read" (16 bytes) for f64 local variables on the stack in rust
some kind of non-stop mode to prevent clickhouse server from losing keeper connection when stepping through the code
allow navigating from source to variables (especially global) and types declared there
allow to put breakpoint on a whole file (by adding breakpoint on the first line, since there's never any real code on first line in practice; have a new icon for it; internally use line 0 to cover the garbage LineInfo-s with line 0; or maybe put breakpoint only on function entry points instead of everything)
handle tail calls: if you step-into a tail call (by single-stepping from instruction pointed by DW_AT_call_pc of a DW_TAG_call_site with DW_AT_call_tail_call), the tail-callee should be added to stack digest (so its stack frame is selected instead of parent)
use actual function name instead of "_" in namespace path, or do something else to make function-static variables usable
show number of function inlined sites in disassembly window, allow setting breakpoint on it, allow opening inline-only functions
follow forks, maybe even support multiple processes
allow cast `foo as typeof(bar)`, also `foo as typeof(bar)::T`
show argument values in stack trace
hotkey to step to end of basic block or next call/ret
key to follow a jump in disas
allow line-based steps in .plt* (maybe by just turning them into single-instruction-steps)
in disassembly window, make 'left' key jump to the start of inlined function
maximizing windows (hot key and button in a corner)
signal breakpoints
make source window autoscroll horizontally in addition to vertically
handle partially-optimized-out struct values (common in rust)
read color scheme from file
color threads based on stack hash
search in watches window
search in disassembly
assigning to debuggee variables and registers, including rip
key to teleport ip to current line

watches, expressions
  first, implement simple expression watches
  second, write many pretty printers in imaginary language, figure out what it should be; std::vector, unordered_map, unique_ptr, shared_ptr, list, optional, Rust Vec, HashMap, Option, Box, deb's Pool, etc; see if per-field format options are needed
  stateful expression interpreter, yield, functions
  associating print expressions with types (by substring match to cover templates?)
  always show raw value as one of the children, including for container elements (yield raw value when recursing)
  print options: hex, raw, array length (expression), expanded (i.e. omit array contents etc)
  maybe: api to output a tree of nested values, skipping subtrees if collapsed (`if $yield(val, nested)`, `$yield((), end)`?)
  manual refresh for slow expressions, exec time limit (press refresh to double the limit and retry)
  special functions/operators like sizeof() ($sizeof()?), type_name, type_offset, type_binary, offsetof, type_of (treating type as value of a special type, expandable in watch window)
  format matrices prettily
  format options for simd registers to show as vectors of given type and length (expandable)
  make basic types like u16 available without big search, with consistent names
  also consider subset of the language for injecting conditional breakpoint code

unfocus search bars when moving up/down the list (but not when scrolling)
show disassembly even if symbols are missing
group threads by stack trace, to make it easy to exclude pool threads waiting for work
show return value after step-out (and other steps that happened to step out)
thread-specific breakpoints (controlled in breakpoints window), a key to lock all breakpoints to current thread
resolve dynamic library call targets in disassembly, instead of showing them as "call .plt.sec+1234h"
research symtab function range overlaps, don't ignore lengths (e.g. in ld-linux-x86-64.so.2, entry point is a NOTYPE symbol _start, which we incorrectly attribute to previous function _dl_help that ends just before the program entry point)
pretty print variable locations (inline frame base and cfa, turn simple expressions from postfix to infix notation)
handle subset of fields being optimized out (seen e.g. for metric_active_threads in ThreadPoolImpl<std::__1::thread>::worker)
maybe show various stop conditions (program start, crashing signals, stepping) uniformly as virtual breakpoints in breakpoints window
test symbols loader with TSAN (for the sketchy bespoke locking in types traversal)
parse and colorize function names, especially the template stuff
parse and colorize type names, especially the template stuff

try refactoring Debugger to move threads outside to avoid re-lookups everywhere
show code in disassembly
show variable names in disassembly
allow opening files that don't exist to put breakpoints before dynamic library load
locking windows
test on very large disassembled functions and large source files
disassembly: show basic block boundaries (jump destinations)
disassembly: show current jump destination like in perf
maybe handle tail calls somehow, for step-over/step-out purposes; probably show it in ui
if a step is interrupted, focus on the stack frame of the step, not the top frame
allow calling functions
refactor loader stack to not contain leaves
snapshots and "step back"; probably don't actually revert the process state, just allow inspecting snapshot of memory+registers
