命令字:!ndx.kallsyms
用法描述
用于显示内核核心符号表信息,相当于cat /proc/kallsyms
不过这里只显示了核心符号模块的信息,模块符号的信息交由!ndx.modsyms完成
命令行参数支持:
-a 按地址查找
-n 按名称查找
-h / ? 帮助信息
开发过程
1.找到关键全局变量
符号数量全局变量:
kallsyms_num_syms 表示内核符号的数量。
地址相关全局变量:
kallsyms_relative_base 符号地址的相对基址。
kallsyms_offsets[] 用于存储符号偏移相关信息。
类型和字符相关全局变量:
kallsyms_names[] 存储内核符号名称相关数据,经过压缩。
kallsyms_token_table[] 存储符号令牌表相关数据。
kallsyms_token_index[] 存储符号令牌索引相关信息。
查找过程
proc_create(“kallsyms”, 0444, NULL, &kallsyms_proc_ops);
在proc文件系统创建了kallsyms文件
kallsyms_proc_ops是roc_ops结构体实例,用于定义/proc/kallsyms文件的操作函数集
例如当你执行 cat /proc/kallsyms时,则调用kallsyms_open这个函数
_seqopen_private(file, &kallsyms_op, sizeof(*iter))
初始化一个用于遍历内核符号表的迭代器,为后续读取或操作内核符号表数据做准备。
注册了 kallsyms_op 中定义的回调函数以处理符号遍历与显示逻辑。
在 void *s_start和void *s_next都是调用update_iter来更新当前迭代器
然后在s_show显示迭代器中存储的信息
在update_iter中,有pos >= kallsyms_num_syms,如果当前遍历的索引已经超过 kallsyms_num_syms(核心符号数量),那说明是模块符号信息,调用模块符号处理函数。
get_ksymbol_core(iter)则从更新当前迭代器的信息。并且返回一个name长度。
get_ksymbol_core()中更新了iter->value(符号地址), iter->type(符号类型),iter->name(符号名)
在kernel\kallsyms_internal.h有更新迭代器涉及的相关全局变量:
2.相关数据结构和实现思路
地址相关数据结构:
偏移数组kallsyms_offsets[],它的大小为kallsyms_num_syms(内核符号的数量)
符号地址 = 基地址 + 偏移数组[index]
符号名和符号类型数据结构:
kallsyms_names:存储压缩的符号名二进制数据,每个符号包含 1-2 字节的长度信息(最高位标识是否需 2 字节)和对应符号片段的压缩字节序列。
kallsyms_token_table:存储预定义的高频符号片段(如前缀、子串),以\0结尾,作为符号拼接的 “字典”。
kallsyms_token_index:256 元素数组,索引为压缩字节值,值为对应片段在kallsyms_token_table中的偏移,实现字节到片段的映射。
内核中当 kallsyms_expand_symbol 函数解析压缩符号:
○ 从 kallsyms_names 中读取符号的长度信息(1-2 字节),确定压缩内容的字节数
○ 遍历每个压缩字节,以字节值为索引查询 kallsyms_token_index,得到对应片段在 kallsyms_token_table 中的位置
○ 根据位置从 kallsyms_token_table 取出具体字符串片段(如 dev_、pci_)
○ 跳过第一个片段(第一个片段为符号类型,这个函数是解析符号名的,所以跳过),拼接后续所有片段形成完整符号名
○ 在结果末尾添加终止符 \0,返回下一个符号的偏移量
3.代码实现:
读取内容较多,每当使用命令的时候就读取一次显示的话,速度太慢,所以我们在第一次读取时将符号信息做缓存,后续都从缓存中直接获取。
为了提高缓存的效率,我们要尽可能能少调用读取的函数,所以都采用批量读取。
#include "ndx.h"
#include <windows.h>
#include <minwindef.h>
#include <WDBGEXTS.H>
#include <cstdio>
#include <vector>
#include <string>
#include <string.h>
#include <cctype>
#include <cstdlib>
#include <cerrno>
#include <wdbgexts.h>
#include <fstream>
#include <iostream>
#include "kallsyms.h"
// ========== 全局变量定义 ==========
SymbolCache symbol_cache;
SymbolManager symbol_manager;
KallsymsAddresses kallsyms_addrs;
/**
* 初始化内核符号地址
* 从调试器中获取所有kallsyms相关变量的地址
*/
static bool init_kallsyms_addresses() {
dprintf("Initializing kallsyms addresses...\n");
bool success = true;
const char* symbol_names[] = {
"kallsyms_offsets", "kallsyms_names", "kallsyms_num_syms",
"kallsyms_token_table", "kallsyms_token_index", "kallsyms_markers",
"kallsyms_relative_base", "kallsyms_seqs_of_names"
};
ULONG64* addresses[] = {
&kallsyms_addrs.kallsyms_offsets, &kallsyms_addrs.kallsyms_names,
&kallsyms_addrs.kallsyms_num_syms, &kallsyms_addrs.kallsyms_token_table,
&kallsyms_addrs.kallsyms_token_index, &kallsyms_addrs.kallsyms_markers,
&kallsyms_addrs.kallsyms_relative_base, &kallsyms_addrs.kallsyms_seqs_of_names
};
for (int i = 0; i < 8; i++) {
char symbol_expr[64];
sprintf_s(symbol_expr, sizeof(symbol_expr), "lk!%s", symbol_names[i]);
if (!GetExpressionEx(symbol_expr, addresses[i], NULL)) {
dprintf("Failed to get %s address\n", symbol_names[i]);
success = false;
}
}
if (success) {
dprintf("All kallsyms addresses initialized successfully\n");
}
return success;
}
// ========== 缓存管理函数 ==========
/**
* 计算符号名称数据的估算大小
* 基于符号数量智能估算所需的缓存大小
*/
static size_t calculate_names_total_size() {
ULONG read;
// 获取符号数量
unsigned int num_syms = 0;
if (!ExtReadMemory(kallsyms_addrs.kallsyms_num_syms, &num_syms, sizeof(num_syms), &read) ||
read != sizeof(num_syms)) {
return 0;
}
// 智能估算:每个符号平均20字节 + 50%安全边距
size_t estimated_size = num_syms * 30;
dprintf("Symbol count: %u, estimated size: %zu bytes (%.2f MB)\n",
num_syms, estimated_size, estimated_size / 1024.0 / 1024.0);
// 限制在缓存大小范围内
if (estimated_size > KALLSYMS_CACHE_SIZE) {
dprintf("WARNING: Estimated size exceeds cache limit, truncating to %d bytes\n", KALLSYMS_CACHE_SIZE);
estimated_size = KALLSYMS_CACHE_SIZE;
}
// 最小64KB保证基本功能
if (estimated_size < 65536) {
estimated_size = 65536;
}
return estimated_size;
}
/**
* 预加载常用Token数据
* 在初始化时预先加载常用的token,减少运行时开销
*/
static bool preload_common_tokens() {
ULONG read;
size_t loaded_count = 0;
dprintf("Preloading common tokens (optimized for 256 tokens)...\n");
// 基于实际情况:token表只有256个有效条目
const int MAX_TOKENS = 256; // 固定为256个token
// 优化1: 批量读取所有256个token索引(一次ExtReadMemory调用)
std::vector<u16> token_offsets(MAX_TOKENS);
if (!ExtReadMemory(kallsyms_addrs.kallsyms_token_index,
token_offsets.data(),
sizeof(u16) * MAX_TOKENS, &read)) {
dprintf("ERROR: Failed to batch read token index table\n");
return false;
}
size_t actual_tokens = read / sizeof(u16);
dprintf("Batch read %zu token indices\n", actual_tokens);
// 优化2: 批量读取token字符串表(针对256个token优化大小)
const size_t TOKEN_TABLE_CHUNK_SIZE = 8192; // 8KB足够覆盖256个token
std::vector<char> token_table_chunk(TOKEN_TABLE_CHUNK_SIZE);
if (!ExtReadMemory(kallsyms_addrs.kallsyms_token_table,
token_table_chunk.data(),
TOKEN_TABLE_CHUNK_SIZE, &read)) {
dprintf("ERROR: Failed to batch read token table\n");
return false;
}
size_t table_chunk_size = read;
dprintf("Batch read %zu bytes of token table \n", table_chunk_size);
// 优化3: 从内存中的数据处理256个token(无需额外ExtReadMemory调用)
size_t fallback_count = 0;
for (size_t i = 0; i < actual_tokens && i < MAX_TOKENS &&
symbol_cache.token_cache_size < TOKEN_CACHE_SIZE; i++) {
// 跳过已缓存的token
if (symbol_cache.find_token(i)) {
continue;
}
u16 token_offset = token_offsets[i];
// 检查偏移是否在我们批量读取的范围内
if (token_offset >= table_chunk_size) {
// 超出范围,使用fallback单独读取
char token_str[32];
if (ExtReadMemory(kallsyms_addrs.kallsyms_token_table + token_offset,
token_str, sizeof(token_str), &read)) {
if (strlen(token_str) > 0) { // 只缓存非空token
symbol_cache.add_token(i, token_str, strlen(token_str));
loaded_count++;
}
}
continue;
}
// 从批量读取的chunk中获取token字符串
const char* token_str = &token_table_chunk[token_offset];
// 确保字符串在chunk范围内且以null结尾
size_t max_len = table_chunk_size - token_offset;
size_t token_len = strnlen(token_str, max_len);
if (token_len < max_len && token_len > 0) { // 找到了完整的非空null结尾字符串
symbol_cache.add_token(i, token_str, token_len);
loaded_count++;
}
}
dprintf("Successfully preloaded %zu tokens \n", loaded_count);
return true;
}
// ========== 缓存管理函数 ==========
/**
* 初始化符号缓存系统
* 第一阶段:基础数据加载和缓存建立
*/
bool initialize_symbol_cache() {
dprintf("Initialize Symbol Cache\n");
// 初始化缓存结构
if (!symbol_cache.initialized) {
symbol_cache.init();
}
// 初始化内核符号地址
if (!init_kallsyms_addresses()) {
dprintf("ERROR: Failed to initialize kallsyms addresses\n");
return false;
}
// 全量读取符号名称数据
if (!read_all_names()) {
dprintf("ERROR: Failed to read all symbol names data\n");
return false;
}
// 预加载常用token数据
if (!preload_common_tokens()) {
dprintf("WARNING: Failed to preload tokens, will load on demand\n");
}
dprintf("Symbol cache initialization completed\n");
// 显示缓存统计信息
dprintf("Names cache size: %.2f MB\n", symbol_cache.names_cache_size / 1024.0 / 1024.0);
dprintf("Token cache entries: %zu\n", symbol_cache.token_cache_size);
return true;
}
/**
* 全量读取符号名称数据
* 一次性读取所有压缩的符号名称数据到缓存中
*/
static bool read_all_names() {
if (symbol_cache.all_names_loaded) {
return true; // 避免重复加载
}
ULONG read;
size_t total_size = calculate_names_total_size();
dprintf("Loading symbol names data (%zu bytes)...\n", total_size);
if (!ExtReadMemory(kallsyms_addrs.kallsyms_names, symbol_cache.names_cache, total_size, &read)) {
dprintf("ERROR: Failed to read symbol names data\n");
return false;
}
symbol_cache.names_cache_start = kallsyms_addrs.kallsyms_names;
symbol_cache.names_cache_size = read;
symbol_cache.all_names_loaded = true;
dprintf("Successfully loaded %zu bytes of symbol names data\n", symbol_cache.names_cache_size);
return true;
}
/**
* 符号名称读取接口
* 兼容性函数,实际执行全量读取
*/
static bool batch_read_names(ULONG64 start_addr, size_t size) {
// 统一使用全量读取策略
if (!symbol_cache.all_names_loaded) {
return read_all_names();
}
return true;
}
// ========== 符号解析函数 ==========
/**
* 解压缩符号名称
* 从压缩的kallsyms_names数据中解压出完整的符号名称
*
* @param off 在kallsyms_names中的偏移量
* @param result 输出缓冲区
* @param maxlen 缓冲区最大长度
* @return 下一个符号的偏移量,失败返回0
*/
static unsigned int kallsyms_expand_symbol(unsigned int off, char* result, size_t maxlen) {
ULONG read;
int len, skipped_first = 0;
u8 data_byte;
// 缓存应该已经在系统初始化时完成,这里不再重复初始化
// 避免清空已预加载的token缓存
//获取符号名在表中的起始位置,off 是相对偏移量,表示符号名在表中的位置
ULONG64 curr_addr = kallsyms_addrs.kallsyms_names + off;
if (!symbol_cache.is_addr_cached(curr_addr)) {
return 0; // 地址超出缓存范围
}
// 读取符号名称长度字节
data_byte = symbol_cache.get_cached_byte(curr_addr);
len = data_byte;
off++;
// 处理扩展长度字节 (MSB=1表示有扩展字节)
if ((len & 0x80) != 0) {
curr_addr = kallsyms_addrs.kallsyms_names + off;
if (!symbol_cache.is_addr_cached(curr_addr)) {
return 0; // 地址超出缓存范围
}
data_byte = symbol_cache.get_cached_byte(curr_addr);
len = (len & 0x7F) | (data_byte << 7);
off++;
}
// 计算下一个符号的偏移量(与内核代码保持一致)
off += len;
// 逐个解压token并组装符号名称
ULONG64 data_addr = kallsyms_addrs.kallsyms_names + off - len; // 重新定位到数据起始位置
while (len > 0) {
// 获取token索引
if (!symbol_cache.is_addr_cached(data_addr)) {
break; // 地址超出缓存范围
}
data_byte = symbol_cache.get_cached_byte(data_addr);
data_addr++;
len--;
// 查找或加载token
TokenCacheEntry* token_entry = symbol_cache.find_token(data_byte);
if (!token_entry) {
// 预加载应该已经覆盖了所有token,这里是fallback
dprintf("WARNING: Token %u not in cache, using fallback loading\n", data_byte);
// Token未缓存,动态加载
u16 token_index_val;
if (!ExtReadMemory(kallsyms_addrs.kallsyms_token_index + data_byte * sizeof(u16),
&token_index_val, sizeof(token_index_val), &read) ||
read != sizeof(token_index_val)) {
break;
}
char token_str[32];
ULONG64 token_addr = kallsyms_addrs.kallsyms_token_table + token_index_val;
if (!ExtReadMemory(token_addr, token_str, sizeof(token_str), &read)) {
break;
}
symbol_cache.add_token(data_byte, token_str, strlen(token_str));
token_entry = symbol_cache.find_token(data_byte);
}
// 复制token字符串到结果缓冲区
if (token_entry) {
const char* tptr = token_entry->str;
while (*tptr) {
if (skipped_first) {
if (maxlen <= 1) goto tail;
*result++ = *tptr;
maxlen--;
}
else {
skipped_first = 1;
}
tptr++;
}
}
}
tail:
if (maxlen > 0) {
*result = '\0';
}
return off; // 返回下一个符号的偏移量
}
/**
* 从缓存中快速获取符号类型字符
*
* @param off 符号在kallsyms_names中的偏移量
* @return 符号类型字符,失败返回'?'
*/
static char get_symbol_type(unsigned int off) {
ULONG read;
// 符号名称数据应该已经在系统初始化时加载完成
// 从缓存中获取符号类型索引(偏移+1位置)
ULONG64 type_addr = kallsyms_addrs.kallsyms_names + off + 1;
if (!symbol_cache.is_addr_cached(type_addr)) {
return '?'; // 地址超出缓存范围
}
u8 type_index = symbol_cache.get_cached_byte(type_addr);
// 优先从token缓存中获取
TokenCacheEntry* token_entry = symbol_cache.find_token(type_index);
if (token_entry && token_entry->len > 0) {
return token_entry->str[0]; // 返回类型字符
}
// 预加载已经覆盖了所有token,这里是fallback
dprintf("WARNING: Symbol type token %u not in cache, using fallback loading\n", type_index);
// Token未缓存,动态加载
u16 token_offset;
if (!ExtReadMemory(kallsyms_addrs.kallsyms_token_index + type_index * sizeof(u16),
&token_offset, sizeof(token_offset), &read) ||
read != sizeof(token_offset)) {
return '?';
}
char token_str[32];
if (!ExtReadMemory(kallsyms_addrs.kallsyms_token_table + token_offset,
token_str, sizeof(token_str), &read)) {
return '?';
}
// 缓存新加载的token
symbol_cache.add_token(type_index, token_str, strlen(token_str));
return token_str[0];
}
/**
* 批量读取符号地址
* 一次性读取指定范围内所有符号的地址
*
* @param start_index 起始符号索引
* @param count 要读取的符号数量
* @param addresses 输出地址数组
* @return 成功返回true
*/
static bool batch_read_addresses(unsigned int start_index, unsigned int count, std::vector<ULONG64>& addresses) {
ULONG read;
// 一次性读取所有偏移量
std::vector<INT32> offsets(count);
if (!ExtReadMemory(kallsyms_addrs.kallsyms_offsets + start_index * sizeof(INT32),
offsets.data(), sizeof(INT32) * count, &read) || read != sizeof(INT32) * count) {
dprintf("ERROR: Failed to read symbol offsets\n");
return false;
}
// 读取相对地址基址
ULONG64 base;
if (!ExtReadMemory(kallsyms_addrs.kallsyms_relative_base, &base, sizeof(base), &read) ||
read != sizeof(base)) {
dprintf("ERROR: Failed to read relative base address\n");
return false;
}
// 计算所有符号的实际地址
addresses.resize(count);
for (unsigned int i = 0; i < count; i++) {
addresses[i] = base + offsets[i];
}
return true;
}
// ========== 符号处理函数 ==========
/**
* 处理所有符号
* 第三阶段:使用优化后的缓存处理符号数据
*/
bool process_all_symbols(unsigned int num_syms, const std::vector<ULONG64>& addresses) {
dprintf("=== Phase 3: Process All Symbols ===\n");
unsigned int off = 0;
unsigned int cached_count = 0;
unsigned int failed_count = 0;
for (unsigned int i = 0; i < num_syms; i++) {
char name[KSYM_NAME_LEN];
char type = get_symbol_type(off);
unsigned int next_off = kallsyms_expand_symbol(off, name, sizeof(name));
if (next_off == 0) {
dprintf("WARNING: Failed to expand symbol at index %d, skipping...\n", i);
failed_count++;
off += 1;
continue;
}
off = next_off;
if (name[0]) {
symbol_manager.symbols.push_back({ addresses[i], type, std::string(name) });
cached_count++;
}
// 显示进度
if ((i + 1) % 10000 == 0) {
dprintf("Progress: %u/%u symbols processed (failed: %u)\n", i + 1, num_syms, failed_count);
}
}
dprintf("Symbol processing completed: %u cached, %u failed\n", cached_count, failed_count);
return cached_count > 0;
}
/**
* 初始化符号缓存系统
* 执行完整的符号表加载和缓存初始化
*/
bool initialize_symbol_system() {
if (symbol_manager.is_initialized) {
return true;
}
dprintf("Symbols are being cached, please wait...\n");
ULONG read;
LARGE_INTEGER init_start, init_end, frequency;
QueryPerformanceFrequency(&frequency);
QueryPerformanceCounter(&init_start);
dprintf("=== Initializing Symbol System ===\n");
// 初始化基础缓存
dprintf("===Stage 1: Setting up basic cache...===\n");
if (!initialize_symbol_cache()) {
dprintf("ERROR: Failed to initialize symbol cache\n");
return false;
}
// 获取符号数量并准备处理
dprintf("=== Stage 2: Preparing symbol processing... ===\n");
unsigned int num_syms = 0;
if (!ExtReadMemory(kallsyms_addrs.kallsyms_num_syms, &num_syms, sizeof(num_syms), &read) ||
read != sizeof(num_syms)) {
dprintf("ERROR: Failed to read number of symbols\n");
return false;
}
dprintf("Found %u symbols to process\n", num_syms);
// 批量读取符号地址
dprintf("=== Stage 3: Loading symbol addresses... ===\n");
std::vector<ULONG64> all_addresses;
if (!batch_read_addresses(0, num_syms, all_addresses)) {
dprintf("ERROR: Failed to read all addresses\n");
return false;
}
// 处理所有符号
dprintf("=== Stage 4: Processing symbols with optimized cache... ===\n");
symbol_manager.symbols.reserve(num_syms);
if (!process_all_symbols(num_syms, all_addresses)) {
dprintf("ERROR: Failed to process symbols\n");
return false;
}
symbol_manager.is_initialized = true;
// 计算初始化总时间
QueryPerformanceCounter(&init_end);
double init_time = (double)(init_end.QuadPart - init_start.QuadPart) / frequency.QuadPart;
dprintf("=== Symbol System Initialization Complete ===\n");
dprintf("Total symbols processed: %u\n", num_syms);
dprintf("Initialization time: %.3f seconds\n", init_time);
dprintf("Processing speed: %.0f symbols/second\n", symbol_manager.symbols.size() / init_time);
return true;
}
// ========== 解析命令和查询函数 ==========
/**
* 解析并执行命令行参数
*/
void parse_and_execute_command(const char* args) {
if (!args || !*args) {
// 无参数时显示所有符号,和帮助信息
show_all_symbols();
show_usage();
return;
}
// 创建参数副本以避免修改原始字符串
char args_copy[256];
strncpy_s(args_copy, sizeof(args_copy), args, _TRUNCATE);
char* token = strtok(args_copy, " ");
if (!token) {
show_usage();
return;
}
// 解析命令选项
if (_stricmp(token, "-n") == 0) {
// 按名称查询
char* symbol_name = strtok(nullptr, " ");
if (symbol_name) {
query_symbol_by_name(symbol_name);
}
else {
dprintf("ERROR: Missing symbol name\n");
show_usage();
}
}
else if (_stricmp(token, "-a") == 0) {
// 按地址查询
char* addr_str = strtok(nullptr, " ");
if (addr_str) {
ULONG64 target_addr = strtoull(addr_str, nullptr, 16);
query_symbol_by_address(target_addr);
}
else {
dprintf("ERROR: Missing address\n");
show_usage();
}
}
else if (_stricmp(token, "-c") == 0) {
// 清空缓存
clear_symbol_cache();
}
else if (_stricmp(token, "-l") == 0 || _stricmp(token, "--list") == 0) {
// 显示所有符号
show_all_symbols();
}
else {
dprintf("ERROR: Unknown option '%s'\n", token);
show_usage();
}
}
/**
* 显示使用帮助
*/
void show_usage() {
dprintf(
"Linux Kernel Symbol Table Commands:\n"
" !ndx.kallsyms Show all symbols (default)\n"
" !ndx.kallsyms -n <symbol_name> Search by symbol name (supports wildcards)\n"
" !ndx.kallsyms -a <address> Search by address (hex format)\n"
" !ndx.kallsyms -c Clear symbol cache\n"
" !ndx.kallsyms -h, -help, ? - Show this help\n"
);
}
/**
* 通配符匹配函数
* 支持前缀匹配(abc*)、后缀匹配(*xyz)、包含匹配(*def*)
*/
static bool wildcard_match(const std::string& text, const std::string& pattern) {
if (pattern.empty()) {
return text.empty();
}
// 检查是否包含通配符
if (pattern.find('*') == std::string::npos) {
// 没有通配符,精确匹配
return text == pattern;
}
// 处理特殊情况:只有一个*
if (pattern == "*") {
return true; // 匹配任何字符串
}
// 【重要】前后缀匹配:*abc* - 必须优先检查,避免被单独的前缀/后缀匹配拦截
if (pattern.front() == '*' && pattern.back() == '*') {
if (pattern.length() <= 2) {
return true; // ** 或 * 匹配任何字符串
}
std::string substring = pattern.substr(1, pattern.length() - 2);
return text.find(substring) != std::string::npos;
}
// 后缀匹配:*abc
if (pattern.front() == '*') {
std::string suffix = pattern.substr(1);
if (suffix.empty()) {
return true; // * 匹配任何字符串
}
if (text.length() < suffix.length()) {
return false;
}
return text.substr(text.length() - suffix.length()) == suffix;
}
// 前缀匹配:abc*
if (pattern.back() == '*') {
std::string prefix = pattern.substr(0, pattern.length() - 1);
if (prefix.empty()) {
return true; // * 匹配任何字符串
}
return text.substr(0, prefix.length()) == prefix;
}
// 精确匹配
return text == pattern;
}
/**
* 按名称查询符号
*/
bool query_symbol_by_name(const char* symbol_name) {
dprintf("Searching for symbol: %s\n", symbol_name);
bool found = false;
size_t match_count = 0;
dprintf("Address Type Symbol\n");
dprintf("================ ==== ======\n");
for (const auto& symbol : symbol_manager.symbols) {
// 使用统一的通配符匹配函数
bool match = wildcard_match(symbol.name, symbol_name);
if (match) {
dprintf("%016llx %c %s\n", symbol.addr, symbol.type, symbol.name.c_str());
found = true;
match_count++;
}
}
if (found) {
dprintf("\nFound %zu matching symbol(s)\n", match_count);
}
else {
dprintf("No symbols found matching: %s\n", symbol_name);
}
return found;
}
/**
* 按地址查询符号
*/
bool query_symbol_by_address(ULONG64 target_addr) {
dprintf("Searching for symbol at address: %016llx\n", target_addr);
// 首先尝试精确匹配
const SymbolInfo* exact_match = nullptr;
for (const auto& symbol : symbol_manager.symbols) {
if (symbol.addr == target_addr) {
exact_match = &symbol;
break;
}
}
if (exact_match) {
dprintf("Address Type Symbol\n");
dprintf("================ ==== ======\n");
dprintf("%016llx %c %s(exact match)\n",
exact_match->addr, exact_match->type, exact_match->name.c_str());
return true;
}
// 如果没有精确匹配,查找最接近的符号
dprintf("No exact match found, searching for nearest symbol...\n");
const SymbolInfo* best_match = nullptr;
ULONG64 best_distance = ULLONG_MAX;
for (const auto& symbol : symbol_manager.symbols) {
if (symbol.addr <= target_addr) {
ULONG64 distance = target_addr - symbol.addr;
if (distance < best_distance) {
best_distance = distance;
best_match = &symbol;
}
}
}
if (best_match) {
dprintf("Address Type Symbol\n");
dprintf("================ ==== ======\n");
dprintf("%016llx %c %s", best_match->addr, best_match->type, best_match->name.c_str());
if (best_distance > 0) {
dprintf(" + 0x%llx (offset: %llu bytes)", best_distance, best_distance);
}
dprintf("\n");
// 如果偏移太大,给出警告
if (best_distance > 0x1000) { // 4KB
dprintf("WARNING: Large offset (0x%llx), symbol may not be related\n", best_distance);
}
return true;
}
else {
dprintf("No symbol found for address: %016llx\n", target_addr);
return false;
}
}
/**
* 显示所有符号
*/
void show_all_symbols() {
size_t total_symbols = symbol_manager.symbols.size();
dprintf("Displaying all %zu symbols:\n\n", total_symbols);
size_t displayed = 0;
for (const auto& symbol : symbol_manager.symbols) {
dprintf("[%06zu] %016llx %c %s\n", displayed + 1, symbol.addr, symbol.type, symbol.name.c_str());
displayed++;
}
dprintf("\n=== End of Symbol Table ===\n");
dprintf("Total symbols displayed: %zu\n", displayed);
}
/**
* 清空符号缓存
*/
void clear_symbol_cache() {
dprintf("Clearing symbol cache...\n");
symbol_manager.symbols.clear();
symbol_manager.is_initialized = false;
symbol_cache.init();
dprintf("Symbol cache cleared successfully\n");
}
// ========== 公共API接口 ==========
/**
* 检查是否为帮助命令,如果是则直接显示帮助并返回true
*/
static bool is_help_command(const char* args) {
if (!args || !*args) {
return false;
}
// 创建参数副本以避免修改原始字符串
char args_copy[256];
strncpy_s(args_copy, sizeof(args_copy), args, _TRUNCATE);
char* token = strtok(args_copy, " ");
if (!token) {
return false;
}
// 检查是否为帮助命令
if (_stricmp(token, "-h") == 0 || _stricmp(token, "--help") == 0 || _stricmp(token, "?") == 0) {
show_usage();
return true;
}
return false;
}
/**
* kallsyms命令实现
* 显示所有内核符号信息
*/
DECLARE_API(kallsyms)
{
// 首先检查是否为帮助命令,如果是则直接显示帮助,无需初始化符号缓存
if (is_help_command(args)) {
return;
}
// 确保符号缓存已初始化
if (!symbol_manager.is_initialized) {
if (!initialize_symbol_system()) {
dprintf("ERROR: Failed to initialize symbol cache system\n");
return;
}
}
//// 写入文件
//FILE* file = nullptr;
//if (fopen_s(&file, "d:\\test\\kallsyms.txt", "w") == 0 && file != nullptr) {
// dprintf("Writing symbols to file: d:\\temp\\kallsyms.txt\n");
// fprintf(file, "=== Linux Kernel Symbol Table ===\n");
// fprintf(file, "Total symbols: %zu\n\n", total_symbols);
// fprintf(file, "Index Address Type Symbol\n");
// fprintf(file, "======= ================ ==== ======\n");
// size_t file_count = 0;
// for (const auto& symbol : symbol_manager.symbols) {
// fprintf(file, "[%06zu] %016llx %c %s\n", file_count + 1, symbol.addr, symbol.type, symbol.name.c_str());
// file_count++;
// }
// fprintf(file, "\n=== End of Symbol Table ===\n");
// fclose(file);
// dprintf("Successfully wrote %zu symbols to file\n", total_symbols);
//}
//else {
// dprintf("ERROR: Failed to create output file c:\\temp\\kallsyms.txt\n");
//}
// 解析并执行相关查询命令
parse_and_execute_command(args);
}
4.实例测试
cat /proc/kallsyms
最后编辑:郭建程 更新时间:2025-09-11 16:05