命令字:!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 09:39
最后编辑:郭建程  更新时间:2025-09-11 16:05