bpf+bpftrace: percpu_kaddr emits ld_imm64 PSEUDO_BTF_ID — verifier-accepted percpu_ptr
The verifier rejected \`bpf_per_cpu_ptr' with \`R1 type=scalar expected=percpu_ptr_*' because we loaded the percpu symbol's address as a plain 64-bit literal (src_reg=0). The kernel needs the address to come from an ld_imm64 marked with src_reg=BPF_PSEUDO_BTF_ID(3): the loader-side patches the imm slots into the runtime address AND the verifier types the destination register as the symbol's actual percpu_ptr_<T>. End-to-end plumbing: * bpf.lisp: \`+bpf-pseudo-btf-id+' (3) and \`emit-ld-btf-id' encode the two-slot instruction with imm0=btf_id and imm1=btf_obj_fd (0 for vmlinux). * vmlinux.lisp: \`btf-find-var' walks BTF for a BTF_KIND_VAR (kernel global with type info) by name. Returns the type-id used as the ld_imm64 imm. * lower.lisp: new builtin form \`(ld-btf-id BTF-ID)' lowers to a \`:mov VREG (:btf-id N)' IR insn. \`*whistler-builtins*' gains \`LD-BTF-ID' so the macro-expander leaves it alone. * emit.lisp: \`emit-mov-insn' recognises \`(:btf-id N)' alongside \`(:imm N)' and routes through \`emit-ld-btf-id'. Reg-allocated to a register directly; stack-spill spills via R0 just like large literals do. * codegen.lisp: \`lower-percpu-kaddr-call' tries BTF first (\`btf-find-var') and emits \`(per-cpu-ptr (ld-btf-id ID) cpu)'. Falls back to the prior kallsyms literal only when the symbol has no BTF entry (verifier will still reject those at load — the caller learns sooner via the helper's diagnostic). ssa-opt's constant propagation only matches \`(:imm N)' arg shapes, so \`(:btf-id N)' loads survive the optimizer intact. \`percpu_kaddr' already had no other path through ssa-opt — no callers do arithmetic on the typed pointer. Resolves \`call.percpu_kaddr this cpu' modulo CAP_BPF.