| 116 | } |
| 117 | |
| 118 | KernelContext resolve_kernel(const PhysicalLayer& phys, const IsfSymbols& isf) { |
| 119 | KernelContext ctx{}; |
| 120 | |
| 121 | // init_task is OPTIONAL: full DWARF-derived ISFs have it (so we can |
| 122 | // derive KASLR shift symbolically); BTF-derived ISFs only carry types, |
| 123 | // so we fall back to direct-from-swapper-scan init_task discovery and a |
| 124 | // best-effort KASLR shift (=0 unless banner symbol is also present). |
| 125 | auto init_task_sym = isf.find_symbol("init_task"); |
| 126 | const bool have_symbols = (init_task_sym != nullptr); |
| 127 | if (!have_symbols) { |
| 128 | log::warn("ISF has no `init_task` symbol — running in BTF/types-only " |
| 129 | "mode. Process listing will work via direct-map; kernel-VA " |
| 130 | "reads (kallsyms, modules, dmesg, DTB walks) will be limited."); |
| 131 | } |
| 132 | |
| 133 | warn_if_isf_mismatch(phys, isf); |
| 134 | |
| 135 | u64 task_struct_size = isf.type_size("task_struct"); |
| 136 | u64 comm_off = isf.field_offset("task_struct", "comm"); |
| 137 | u64 pid_off = isf.field_offset("task_struct", "pid"); |
| 138 | u64 tgid_off = isf.field_offset("task_struct", "tgid"); |
| 139 | u64 tasks_off = isf.field_offset("task_struct", "tasks"); |
| 140 | |
| 141 | if (have_symbols) |
| 142 | log::debug("init_task VA (pre-KASLR) = {:#x}", init_task_sym->address); |
| 143 | log::debug("task_struct: size={:#x} pid@{:#x} comm@{:#x} tasks@{:#x}", |
| 144 | task_struct_size, pid_off, comm_off, tasks_off); |
| 145 | |
| 146 | // First try a banner-based shift (robust against task_struct layout drift). |
| 147 | auto banner_candidates = banner_candidate_shifts(phys, isf); |
| 148 | log::debug("Banner string found at {} location(s)", banner_candidates.size()); |
| 149 | for (auto& [at, sh] : banner_candidates) { |
| 150 | bool aligned_2mb = (sh & 0x1FFFFF) == 0; |
| 151 | log::debug(" banner @ PA {:#x} shift={:#x} 2MB-aligned={}", at, sh, aligned_2mb); |
| 152 | } |
| 153 | |
| 154 | auto hits = scan_swapper(phys); |
| 155 | if (hits.empty()) throw_error("kernel: no swapper signature found"); |
| 156 | |
| 157 | const VAddr init_task_sym_addr = have_symbols ? init_task_sym->address : 0; |
| 158 | |
| 159 | for (PAddr comm_pa : hits) { |
| 160 | PAddr task_pa = (comm_pa >= comm_off) ? (comm_pa - comm_off) : 0; |
| 161 | |
| 162 | u32 pid = 0; |
| 163 | bool ok_pid = phys.read_pod(task_pa + pid_off, pid); |
| 164 | u64 next = 0, prev = 0; |
| 165 | bool ok_next = phys.read_pod(task_pa + tasks_off + 0, next); |
| 166 | bool ok_prev = phys.read_pod(task_pa + tasks_off + 8, prev); |
| 167 | |
| 168 | // dump the comm bytes for sanity |
| 169 | char buf[24] = {}; |
| 170 | phys.read(comm_pa, buf, 16); |
| 171 | log::debug("comm bytes @ {:#x}: '{}' (raw: {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x})", |
| 172 | comm_pa, buf, (u8)buf[0],(u8)buf[1],(u8)buf[2],(u8)buf[3],(u8)buf[4], |
| 173 | (u8)buf[5],(u8)buf[6],(u8)buf[7],(u8)buf[8]); |
| 174 | log::debug("candidate: comm_pa={:#x} task_pa={:#x} pid={} (ok={}) next={:#x} prev={:#x} (ok={},{})", |
| 175 | comm_pa, task_pa, pid, ok_pid, next, prev, ok_next, ok_prev); |
no test coverage detected