| 131 | } |
| 132 | |
| 133 | ByteBuf format_kstack(const Engine& eng, const Process& p) { |
| 134 | auto tr = walk_kernel_stack(eng, p); |
| 135 | std::string out; |
| 136 | out.reserve(4 * 1024); |
| 137 | if (!tr.ok) { |
| 138 | out = fmt::format("; pid {} ({}) — no kernel stack readable\n" |
| 139 | "; (kernel task with no `stack` pointer, or " |
| 140 | "direct-map unreadable)\n", |
| 141 | p.pid, p.comm); |
| 142 | return ByteBuf(out.begin(), out.end()); |
| 143 | } |
| 144 | out += fmt::format( |
| 145 | "# /proc/{}/kstack.txt — kernel-stack walk for pid {} ({})\n" |
| 146 | "# stack base = {:#018x}, thread.sp = {:#018x}\n" |
| 147 | "# {} unique kernel-text return addresses found on the stack\n" |
| 148 | "# (lower offset = closer to currently-executing frame)\n" |
| 149 | "#\n" |
| 150 | "# offset return_addr symbol (+offset)\n" |
| 151 | "# ------ -------------------- -------------------------\n", |
| 152 | p.pid, p.pid, p.comm, |
| 153 | tr.stack_base, tr.thread_sp, tr.frames.size()); |
| 154 | for (const auto& f : tr.frames) { |
| 155 | std::string sym = f.distance == 0 |
| 156 | ? f.symbol |
| 157 | : fmt::format("{} +{:#x}", f.symbol, f.distance); |
| 158 | out += fmt::format(" {:#06x} {:#018x} {}\n", |
| 159 | f.offset_in_stack, f.return_addr, sym); |
| 160 | } |
| 161 | return ByteBuf(out.begin(), out.end()); |
| 162 | } |
| 163 | |
| 164 | } // namespace lmpfs::linux |
no test coverage detected