命令字:!ndx.dyndbg

用法描述

参数情况 对应linux操作 作用
无参数 cat /proc/dynamic_debug/control 列出所有注册的调试项(_ddebug 结构体),包括模块名、文件名、函数名、行号、格式字符串及当前标志位(如 p、m 等)。
带参数 +p(如 !ndx.dyndbg -m ext4 +p) sudo echo ‘module ext4 +p’ > /proc/dynamic_debug/control 对指定条件(如模块 ext4)的调试项执行标志位操作,+p 表示启用这些调试项的打印功能。

支持的命令行参数:
-m <模块名> 按模块名筛选动态调试条目
-s < 文件名 > 按源代码文件名筛选动态调试条目
-f < 函数名 > 按函数名筛选动态调试条目
-t < 格式串 > 按日志格式字符串筛选动态调试条目
-l < 行号 > 按源代码行号筛选动态调试条目
-c < 类名 > 按调试类名筛选动态调试条目
-h /–help/ ? 显示帮助信息
标志位操作:
+p 启用调试日志打印功能
-p 禁用调试日志打印功能
+m 日志中包含模块名信息
+f 日志中包含函数名信息
+l 日志中包含源代码行号信息
+t 日志中包含线程 ID 信息

开发过程

1. 找到关键全局变量

关键全局变量 作用
ddebug_tables 内核动态调试核心链表头,挂载所有动态调试表,是访问动态调试项的入口。
opt_array 存储动态调试标志(如打印使能、模块名显示等)元信息的数组,用于解析标志操作、描述标志状态。

show

dynamic_debug_init_control为动态调试功能在两种文件系统(debugfs 和 procfs)中建立控制接口

以procfs为例:
proc_open:指定打开 proc 文件时的回调函数 ddebug_proc_open
seq_open_private 是内核提供的函数,用于初始化 seq_file 相关的文件操作
struct seq_operations 是 seq_file 机制的核心操作集合,用于定义遍历、显示数据等行为

dp = ddebug_iter_first(iter)
作用:获取第一个要遍历的数据项。
dp = ddebug_iter_next(iter)
作用:获取下一个要遍历的数据项。

iter->table = list_entry(ddebug_tables.next,struct ddebug_table, link);
这里取了ddebug_tables.next作为链表的头节点,是链表的起始位置;
return &iter->table->ddebugs[–iter->idx];
然后获取链表节点(结构体)中的对应数组的最后一个元素,遍历数组是从后往前

wirte

当你执行命令sudo echo ‘module ext4 +p’ > /proc/dynamic_debug/control 这里+p 表示启用这些调试项的打印功能。会调用相对应的写回调函数 ddebug_proc_write。
我们要实现类似的功能需要执行写内存。

ddebug_proc_write中ddebug_exec_queries 会解析并执行用户输入

ddebug_exec_queries处理调试查询的核心函数。其主要作用是解析查询字符串、验证查询格式,并执行实际的调试配置变更操作。

ddebug_tokenize
作用:将输入的字符串(query_string)按空格分割为多个 “token(词段)”,存储到数组 words 中。
ddebug_parse_flags
作用:解析命令中的 “标志位操作”(比如 +p、-m、=t 等),提取要修改的调试标志(如打印使能、模块名显示等)。
ddebug_parse_query
作用:解析命令中除 “标志位操作” 外的其他 token,提取 “筛选条件”(比如模块名 module ext4、文件名 file fs.c、函数名 func mount 等)。

设置标志位:遍历opt_array数组,将输入字符串中匹配的标志字符转换为对应的标志位,存储在modifiers->flags中,实现标志的识别与收集。
设置掩码:
=:掩码设为 0,直接用flags覆盖原有标志
+:掩码设为全 1,在原有标志基础上添加flags
-:掩码设为flags的取反,同时清空flags,实现从原有标志中移除指定标志
![]

在 ddebug_change函数中通过标志位和掩码获取最新的标志位

2. 相关数据结构

struct ddebug_table {
    struct list_head link, maps;
    const char *mod_name;
    unsigned int num_ddebugs;
    struct _ddebug *ddebugs;
};
struct _ddebug {
    /* 用于驱动调试调用点的选择和显示的UI字段 */
    const char *modname;        // 模块名
    const char *function;       // 函数名
    const char *filename;       // 文件名
    const char *format;         // 调试信息格式字符串
    unsigned int lineno:18;     // 行号(18位)
    #define CLS_BITS 6             // 分类ID位数
    unsigned int class_id:CLS_BITS; // 分类ID(6位)
    #define _DPRINTK_CLASS_DFLT    ((1 << CLS_BITS) - 1) // 默认分类ID(63)

    /* 标志位控制调用点行为,可通过debugfs动态修改 */
    #define _DPRINTK_FLAGS_NONE    0                   // 无标志
    #define _DPRINTK_FLAGS_PRINT    (1<<0)              // 允许输出调试信息
    #define _DPRINTK_FLAGS_INCL_MODNAME    (1<<1)       // 输出包含模块名
    #define _DPRINTK_FLAGS_INCL_FUNCNAME    (1<<2)      // 输出包含函数名
    #define _DPRINTK_FLAGS_INCL_LINENO    (1<<3)       // 输出包含行号
    #define _DPRINTK_FLAGS_INCL_TID        (1<<4)       // 输出包含线程ID

    #define _DPRINTK_FLAGS_INCL_ANY        \
    (_DPRINTK_FLAGS_INCL_MODNAME | _DPRINTK_FLAGS_INCL_FUNCNAME |
     _DPRINTK_FLAGS_INCL_LINENO  | _DPRINTK_FLAGS_INCL_TID) // 所有附加信息标志

    #if defined DEBUG
    #define _DPRINTK_FLAGS_DEFAULT _DPRINTK_FLAGS_PRINT // DEBUG模式默认允许输出
    #else
    #define _DPRINTK_FLAGS_DEFAULT 0                   // 非DEBUG模式默认禁止输出
    #endif
    unsigned int flags:8;       // 控制标志(8位)

    #ifdef CONFIG_JUMP_LABEL
    union {                     // 动态跳转优化用静态键
        struct static_key_true dd_key_true;
        struct static_key_false dd_key_false;
    } key;
    #endif
} __attribute__((aligned(8))); // 8字节对齐,提升访问效率

3.总体思路:

show
遍历链表获取每个节点,再遍历节点中的数组(从后往前)
write
解析参数,按照内核方式修改标志位(调用写内存的api函数)

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 <fstream>
#include <iostream>

#include "dyndbg.h"


// 标志位描述结构体
struct flagsbuf {
    char buf[8];
};

// 标志位设置结构体(仿照内核实现)
struct flag_settings {
    unsigned int flags;  // 要设置的标志位
    unsigned int mask;   // 掩码
};

// 命令行参数解析结构体
struct ddebug_query {
    const char* modname;      // 模块名 (-m)
    const char* filename;     // 文件名 (-s)
    const char* function;     // 函数名 (-f)
    const char* format;       // 格式字符串 (-t)
    const char* class_name;   // 类名 (-c)
    unsigned int lineno;      // 行号 (-l)
    struct flag_settings modifiers;  // 标志位修改器
    bool has_flags_op;        // 是否有标志位操作

    // 构造函数初始化
    ddebug_query() : modname(nullptr), filename(nullptr), function(nullptr),
        format(nullptr), class_name(nullptr), lineno(0),
        has_flags_op(false) {
        modifiers.flags = 0;
        modifiers.mask = 0;
    }
};

/**
 * 计算新的标志位(仿照内核逻辑)
 */
unsigned int calculate_new_flags(unsigned int old_flags, const struct flag_settings* modifiers) {
    return (old_flags & modifiers->mask) | modifiers->flags;
}

/**
 * 解析标志位字符串(仿照内核ddebug_parse_flags实现)
 */
int ddebug_parse_flags(const char* str, struct flag_settings* modifiers) {
    int op, i;
    const char* orig_str = str;

    if (!str || !modifiers) {
        return -1;
    }

    // 初始化modifiers
    modifiers->flags = 0;
    modifiers->mask = 0;

    // 解析操作符
    switch (*str) {
    case '+':
    case '-':
    case '=':
        op = *str++;
        break;
    default:
        dprintf("ERROR: bad flag-op %c, at start of %s\n", *str, orig_str);
        return -1;
    }

    dprintf("op='%c'\n", op);

    // 解析标志位字符
    for (; *str; ++str) {
        for (i = sizeof(opt_array) / sizeof(opt_array[0]) - 1; i >= 0; i--) {
            if (*str == opt_array[i].opt_char) {
                modifiers->flags |= opt_array[i].flag;
                break;
            }
        }
        if (i < 0) {
            dprintf("ERROR: unknown flag '%c'\n", *str);
            return -1;
        }
    }

    dprintf("flags=0x%x\n", modifiers->flags);

    // 根据操作符计算最终的flags和mask
    switch (op) {
    case '=':
        // modifiers->flags already set
        modifiers->mask = 0;
        break;
    case '+':
        modifiers->mask = ~0U;
        break;
    case '-':
        modifiers->mask = ~modifiers->flags;
        modifiers->flags = 0;
        break;
    }

    dprintf("*flagsp=0x%x *maskp=0x%x\n", modifiers->flags, modifiers->mask);

    return 0;
}

/**
 * 解析标志位字符串的包装函数
 */
bool parse_flags(const char* flags_str, ddebug_query* query) {
    if (!flags_str || !query) {
        return false;
    }

    query->has_flags_op = true;

    return ddebug_parse_flags(flags_str, &query->modifiers) == 0;
}

/**
 * 解析完整的命令行参数
 */
bool parse_ddebug_command(const char* args, ddebug_query* query) {
    if (!args || !query) {
        return false;
    }

    // 创建参数副本
    char args_copy[512];
    strncpy_s(args_copy, sizeof(args_copy), args, _TRUNCATE);

    char* token = strtok(args_copy, " ");

    while (token != nullptr) {
        if (strncmp(token, "-m", 2) == 0) {
            // 模块名
            if (strlen(token) > 2) {
                query->modname = _strdup(token + 2);  // 跳过-m
            }
            else {
                token = strtok(nullptr, " ");
                if (token) {
                    query->modname = _strdup(token);
                }
            }
        }
        else if (strncmp(token, "-s", 2) == 0) {
            // 文件名
            if (strlen(token) > 2) {
                query->filename = _strdup(token + 2);
            }
            else {
                token = strtok(nullptr, " ");
                if (token) {
                    query->filename = _strdup(token);
                }
            }
        }
        else if (strncmp(token, "-f", 2) == 0) {
            // 函数名
            if (strlen(token) > 2) {
                query->function = _strdup(token + 2);
            }
            else {
                token = strtok(nullptr, " ");
                if (token) {
                    query->function = _strdup(token);
                }
            }
        }
        else if (strncmp(token, "-l", 2) == 0) {
            // 行号
            if (strlen(token) > 2) {
                query->lineno = atoi(token + 2);
            }
            else {
                token = strtok(nullptr, " ");
                if (token) {
                    query->lineno = atoi(token);
                }
            }
        }
        else if (strncmp(token, "-c", 2) == 0) {
            // 类名
            if (strlen(token) > 2) {
                query->class_name = _strdup(token + 2);
            }
            else {
                token = strtok(nullptr, " ");
                if (token) {
                    query->class_name = _strdup(token);
                }
            }
        }
        else if (strncmp(token, "-t", 2) == 0) {
            // 格式字符串
            if (strlen(token) > 2) {
                query->format = _strdup(token + 2);
            }
            else {
                token = strtok(nullptr, " ");
                if (token) {
                    query->format = _strdup(token);
                }
            }
        }
        else if (token[0] == '+' || token[0] == '-') {
            // 标志位操作
            if (!parse_flags(token, query)) {
                return false;
            }
        }
        else {
            dprintf("ERROR: Unknown parameter '%s'\n", token);
            return false;
        }

        token = strtok(nullptr, " ");
    }

    return true;
}

/**
 * 释放ddebug_query结构体中分配的内存
 */
void free_ddebug_query(ddebug_query* query) {
    if (!query) return;

    if (query->modname) free((void*)query->modname);
    if (query->filename) free((void*)query->filename);
    if (query->function) free((void*)query->function);
    if (query->format) free((void*)query->format);
    if (query->class_name) free((void*)query->class_name);

    // 重置指针
    query->modname = nullptr;
    query->filename = nullptr;
    query->function = nullptr;
    query->format = nullptr;
    query->class_name = nullptr;
}



// 提取文件名(去除路径)的辅助函数
static const char* extract_filename(const char* filepath) {
    if (!filepath) return nullptr;

    const char* filename = filepath;
    const char* p = filepath;

    // 查找最后一个路径分隔符
    while (*p) {
        if (*p == '/' || *p == '\\') {
            filename = p + 1;
        }
        p++;
    }

    return filename;
}

// 描述标志位的函数
static char* ddebug_describe_flags(unsigned int flags, struct flagsbuf* fb) {
    char* p = fb->buf;
    int i;

    // 处理所有非零标志位
    for (i = 0; i < sizeof(opt_array) / sizeof(opt_array[0]) - 1; ++i) {
        if (flags & opt_array[i].flag)
            *p++ = opt_array[i].opt_char;
    }

    // 如果没有设置任何标志位,使用_DPRINTK_FLAGS_NONE对应的字符
    if (p == fb->buf)
        *p++ = opt_array[sizeof(opt_array) / sizeof(opt_array[0]) - 1].opt_char;
    *p = '\0';

    return fb->buf;
}


DynDbg::DynDbg() {

}


// 处理单个_ddebug结构体(通过地址)
bool DynDbg::process_ddebug_impl(ULONG64 ddebug_addr, const char* mod_name, ULONG64 table_addr) {
    _ddebug dp;
    if (!ExtReadMemory(ddebug_addr, &dp, sizeof(dp), NULL)) {
        dprintf("ERROR: Failed to read _ddebug structure at 0x%I64x\n", ddebug_addr);
        return false;
    }

    // 调用函数处理结构体
    return process_ddebug_impl(dp, mod_name, table_addr);
}

// 处理单个_ddebug结构体(直接传递结构体)
bool DynDbg::process_ddebug_impl(const _ddebug& dp, const char* mod_name, ULONG64 table_addr) {
    unsigned int lineno = dp.lineno;
    unsigned int class_id = dp.class_id;
    ULONG flags = dp.flags;

    // 读取字符串字段
    char function[256] = { 0 };
    if (dp.function && !ExtReadMemory((ULONG64)dp.function, function, sizeof(function), NULL)) {
        dprintf("WARNING: Failed to read _ddebug.function string at 0x%I64x\n", (ULONG64)dp.function);
        return query_only_mode ? false : true;
    }

    char filename[256] = { 0 };
    if (dp.filename && !ExtReadMemory((ULONG64)dp.filename, filename, sizeof(filename), NULL)) {
        dprintf("WARNING: Failed to read _ddebug.filename string at 0x%I64x\n", (ULONG64)dp.filename);
        return query_only_mode ? false : true;
    }

    char format[256] = { 0 };
    if (dp.format && !ExtReadMemory((ULONG64)dp.format, format, sizeof(format), NULL)) {
        dprintf("WARNING: Failed to read _ddebug.format string at 0x%I64x\n", (ULONG64)dp.format);
        return query_only_mode ? false : true;
    }

    // 如果是查询模式,打印信息
    if (query_only_mode) {
        // 格式化输出
        struct flagsbuf fb;

        // 去除format字符串中的换行符,避免双引号独自成行
        char clean_format[256] = { 0 };
        if (strlen(format) > 0) {
            strncpy(clean_format, format, sizeof(clean_format) - 1);
            // 将换行符替换为空格
            for (char* p = clean_format; *p; p++) {
                if (*p == '\n' || *p == '\r') {
                    *p = ' ';
                }
            }
        }

        dprintf("%s:%u [%s]%s =%s \"%s\"",
            filename, lineno,  // 使用完整文件名路径
            mod_name ? mod_name : "unknown", function,
            ddebug_describe_flags(flags, &fb),
            clean_format);

        // 如果class_id不是默认值,尝试获取类名
        if (class_id != _DPRINTK_CLASS_DFLT) {
            const char* class_name = ddebug_class_name_impl(table_addr, class_id);
            if (class_name) {
                dprintf(" class:%s", class_name);
            }
            else {
                dprintf(" class unknown, _id:%u", class_id);
            }
        }
        dprintf("\n");
    }
    // 如果是更新模式且有查询条件,执行匹配和更新
    else if (current_query && current_query->has_flags_op) {
        // 执行匹配检查
        bool match = true;

        // 检查模块名
        if (current_query->modname && mod_name) {
            if (strstr(mod_name, current_query->modname) == NULL) {
                match = false;
            }
        }

        // 检查文件名
        if (match && current_query->filename) {
            const char* file_basename = extract_filename(filename);
            if (!file_basename || strstr(file_basename, current_query->filename) == NULL) {
                match = false;
            }
            else {
                // 找到匹配的文件名,设置标志
                found_matching_file = true;
            }
        }

        // 检查函数名
        if (match && current_query->function) {
            if (strstr(function, current_query->function) == NULL) {
                match = false;
            }
        }

        // 检查格式字符串
        if (match && current_query->format) {
            if (strstr(format, current_query->format) == NULL) {
                match = false;
            }
        }

        // 检查行号
        if (match && current_query->lineno > 0) {
            if (dp.lineno != current_query->lineno) {
                match = false;
            }
        }

        if (match) {
            // 匹配成功,计算新的flags值
            unsigned int old_flags = dp.flags;
            unsigned int new_flags = calculate_new_flags(old_flags, &current_query->modifiers);

            // 计算flags字段在_ddebug结构体中的偏移量
            ULONG flags_offset = 0;
            if (GetFieldOffset("_ddebug", "flags", &flags_offset) != 0) {
                dprintf("ERROR: Failed to get offset of flags field in _ddebug structure\n");
                return false;
            }

            // 计算当前_ddebug结构体的地址(需要从process_ddebug_table_impl传递)
            // 这里需要修改调用方式来传递地址
            // 暂时跳过实际写入,只计数
            updated_count++;

            // 输出匹配和更新信息
            struct flagsbuf fb_old, fb_new;
            dprintf("UPDATED: %s:%u [%s]%s flags: %s -> %s\n",
                filename, dp.lineno, mod_name ? mod_name : "unknown", function,
                ddebug_describe_flags(old_flags, &fb_old),
                ddebug_describe_flags(new_flags, &fb_new));
        }
    }

    return true;
}

// 处理单个_ddebug结构体的实现(带地址版本,用于更新模式)
bool DynDbg::process_ddebug_impl_with_addr(ULONG64 ddebug_addr, const _ddebug& dp, const char* mod_name, ULONG64 table_addr) {
    if (!current_query || !current_query->has_flags_op) {
        return false;
    }

    // 读取字符串字段进行匹配
    char function[256] = { 0 };
    if (dp.function && !ExtReadMemory((ULONG64)dp.function, function, sizeof(function), NULL)) {
        dprintf("WARNING: Failed to read _ddebug.function string at 0x%I64x\n", (ULONG64)dp.function);
        return true;
    }

    char filename[256] = { 0 };
    if (dp.filename && !ExtReadMemory((ULONG64)dp.filename, filename, sizeof(filename), NULL)) {
        dprintf("WARNING: Failed to read _ddebug.filename string at 0x%I64x\n", (ULONG64)dp.filename);
        return true;
    }

    char format[256] = { 0 };
    if (dp.format && !ExtReadMemory((ULONG64)dp.format, format, sizeof(format), NULL)) {
        dprintf("WARNING: Failed to read _ddebug.format string at 0x%I64x\n", (ULONG64)dp.format);
        return true;
    }

    // 执行匹配检查
    bool match = true;

    // 检查模块名
    if (current_query->modname && mod_name) {
        if (strstr(mod_name, current_query->modname) == NULL) {
            match = false;
        }
    }

    // 检查文件名
    if (match && current_query->filename) {
        const char* file_basename = extract_filename(filename);
        if (!file_basename || strstr(file_basename, current_query->filename) == NULL) {
            match = false;
        }
        else {
            // 找到匹配的文件名,设置标志
            found_matching_file = true;
        }
    }

    // 检查函数名
    if (match && current_query->function) {
        if (strstr(function, current_query->function) == NULL) {
            match = false;
        }
    }

    // 检查格式字符串
    if (match && current_query->format) {
        if (strstr(format, current_query->format) == NULL) {
            match = false;
        }
    }

    // 检查行号
    if (match && current_query->lineno > 0) {
        if (dp.lineno != current_query->lineno) {
            match = false;
        }
    }

    if (!match) {
        return true;  // 不匹配时返回true,避免WARNING
    }

    // 匹配成功,计算新的flags值
    unsigned int old_flags = dp.flags;
    unsigned int new_flags = calculate_new_flags(old_flags, &current_query->modifiers);

    // 计算flags字段在_ddebug结构体中的偏移量
    ULONG flags_offset = 0;
    if (GetFieldOffset("_ddebug", "flags", &flags_offset) != 0) {
        dprintf("ERROR: Failed to get offset of flags field in _ddebug structure\n");
        return false;
    }

    // 写入新的flags值
    ULONG64 flags_addr = ddebug_addr + flags_offset;
    dprintf("ddebug_addr=0x%I64x\n", ddebug_addr);
    dprintf("flags_addr=0x%I64x\n", flags_addr);
    dprintf("flags_offset=0x%lx\n", flags_offset);
    if (!ExtWriteMemory(flags_addr, &new_flags, sizeof(new_flags), NULL)) {
        dprintf("ERROR: Failed to write new flags value 0x%x to address 0x%I64x\n", new_flags, flags_addr);
        return false;
    }

    // 更新计数
    updated_count++;

    // 输出匹配和更新信息
    struct flagsbuf fb_old, fb_new;
    dprintf("UPDATED: %s:%u [%s]%s flags: %s -> %s\n",
        filename, dp.lineno, mod_name ? mod_name : "unknown", function,
        ddebug_describe_flags(old_flags, &fb_old),
        ddebug_describe_flags(new_flags, &fb_new));

    return true;
}

// 获取类名的函数实现
const char* DynDbg::ddebug_class_name_impl(ULONG64 table_addr, unsigned int class_id) {
    if (!table_addr || class_id == _DPRINTK_CLASS_DFLT) {
        return NULL;
    }

    // 读取ddebug_table结构体
    struct ddebug_table table_data;
    if (!ExtReadMemory(table_addr, &table_data, sizeof(table_data), NULL)) {
        dprintf("WARNING: Failed to read ddebug_table at 0x%I64x\n", table_addr);
        return NULL;
    }

    // 读取maps链表头
    struct list_head maps_head = table_data.maps;
    ULONG64 maps_head_addr = (ULONG64)&table_data.maps - (ULONG64)&table_data + table_addr;

    // 遍历maps链表
    ULONG64 current_map_node = (ULONG64)maps_head.next;

    // 检查是否为空链表
    if (current_map_node == maps_head_addr || current_map_node == 0) {
        return NULL;
    }

    // 遍历所有类映射
    while (current_map_node != 0 && current_map_node != maps_head_addr) {
        // 计算ddebug_class_map结构体地址
        ULONG64 map_addr = current_map_node - offsetof(struct ddebug_class_map, link);

        // 读取ddebug_class_map结构体
        struct {
            struct list_head link;
            struct module* mod;
            const char* mod_name;
            const char** class_names;
            int length;
            int base;
            int map_type;
        } map_data;

        if (!ExtReadMemory(map_addr, &map_data, sizeof(map_data), NULL)) {
            dprintf("WARNING: Failed to read ddebug_class_map at 0x%I64x\n", map_addr);
            break;
        }

        // 检查class_id是否在此映射范围内
        if (class_id >= map_data.base && class_id < map_data.base + map_data.length) {
            // 计算在数组中的索引
            int index = class_id - map_data.base;

            // 读取类名指针数组
            ULONG64 class_names_addr = (ULONG64)map_data.class_names;
            ULONG64 class_name_ptr_addr = class_names_addr + index * sizeof(const char*);
            const char* class_name_ptr = NULL;

            if (!ExtReadMemory(class_name_ptr_addr, &class_name_ptr, sizeof(class_name_ptr), NULL)) {
                dprintf("WARNING: Failed to read class_name pointer at 0x%I64x\n", class_name_ptr_addr);
                break;
            }

            // 如果找到了类名指针,读取类名字符串
            if (class_name_ptr) {
                static char class_name[256] = { 0 };
                if (ExtReadMemory((ULONG64)class_name_ptr, class_name, sizeof(class_name), NULL)) {
                    return class_name;
                }
            }

            break;
        }

        // 移动到下一个节点
        struct list_head next_node;
        if (!ExtReadMemory(current_map_node, &next_node, sizeof(next_node), NULL)) {
            dprintf("WARNING: Failed to read next map node at 0x%I64x\n", current_map_node);
            break;
        }

        current_map_node = (ULONG64)next_node.next;
    }

    return NULL;
}


// 处理ddebug_table结构体
bool DynDbg::process_ddebug_table_impl(ULONG64 table_addr) {


    // 一次性读取整个结构体
    struct ddebug_table table_data = { 0 };
    if (!ExtReadMemory(table_addr, &table_data, sizeof(table_data), NULL)) {
        dprintf("ERROR: Failed to read ddebug_table structure at 0x%I64x\n", table_addr);
        return false;
    }

    // 提取所需数据
    unsigned int num_ddebugs = table_data.num_ddebugs;
    ULONG64 ddebugs_ptr = (ULONG64)table_data.ddebugs;
    const char* mod_name = table_data.mod_name;

    // 读取模块名称字符串
    char mod_name_str[256] = { 0 };
    if (mod_name) {
        if (!ExtReadMemory((ULONG64)mod_name, mod_name_str, sizeof(mod_name_str), NULL)) {
            dprintf("WARNING: Failed to read module name string at 0x%I64x\n", (ULONG64)mod_name);
            mod_name_str[0] = '\0';
        }
        else {
            dprintf("Processing ddebug_table for module: %s\n", mod_name_str);
        }
    }

    // 在更新模式下,如果指定了模块名且不匹配,直接返回
    if (!query_only_mode && current_query && current_query->modname) {
        if (!mod_name_str[0] || strstr(mod_name_str, current_query->modname) == NULL) {
            return true; // 返回true表示正常处理,但跳过此模块
        }
        // 找到匹配的模块,处理完成后需要设置停止标志
    }




    // 获取_ddebug结构体大小
    ULONG ddebug_size = GetTypeSize("_ddebug");
    if (ddebug_size == 0) {
        dprintf("WARNING: Failed to get size of _ddebug structure\n");
        return false;
    }


    // 计算整个_ddebug数组的大小
    ULONG64 array_size = table_data.num_ddebugs * ddebug_size;

    if (array_size == 0) {
        dprintf("No debug entries to process (empty array)\n");
        return true;
    }

    // 一次性读取整个_ddebug数组,使用KernelDdebug结构体数组
    _ddebug* ddebug_array = new _ddebug[table_data.num_ddebugs];
    if (!ddebug_array) {
        dprintf("ERROR: Failed to allocate memory for ddebug array (%llu bytes)\n", array_size);
        return false;
    }

    // 读取整个数组
    ULONG bytes_read = 0;
    if (!ExtReadMemory(ddebugs_ptr, ddebug_array, (ULONG)array_size, &bytes_read)) {
        dprintf("ERROR: Failed to read ddebug array at 0x%I64x\n", ddebugs_ptr);
        delete[] ddebug_array;
        return false;
    }

    // 处理每个_ddebug结构体(从后往前遍历)
    for (LONG i = (LONG)num_ddebugs - 1; i >= 0; i--) {
        ULONG64 ddebug_addr = ddebugs_ptr + i * ddebug_size;

        // 如果是更新模式且有查询条件,需要传递地址进行实际写入
        if (!query_only_mode && current_query && current_query->has_flags_op) {
            if (!process_ddebug_impl_with_addr(ddebug_addr, ddebug_array[i], mod_name_str[0] ? mod_name_str : NULL, table_addr)) {
                dprintf("WARNING: Failed to process ddebug at index %ld\n", i);
            }
        }
        else {
            if (!process_ddebug_impl(ddebug_array[i], mod_name_str[0] ? mod_name_str : NULL, table_addr)) {
                dprintf("WARNING: Failed to process ddebug at index %ld\n", i);
            }
        }
    }

    delete[] ddebug_array;

    // 在更新模式下,如果指定了模块名且找到了匹配的模块,设置停止遍历标志
    if (!query_only_mode && current_query && current_query->modname &&
        mod_name_str[0] && strstr(mod_name_str, current_query->modname) != NULL) {
        stop_traversal = true;
    }

    // 在更新模式下,如果指定了文件名且找到了匹配的文件,设置停止遍历标志
    if (!query_only_mode && current_query && current_query->filename && found_matching_file) {
        stop_traversal = true;
    }

    return true;
}

// 遍历ddebug_tables链表
bool traverse_ddebug_tables(ULONG64 ddebug_tables_addr, DynDbg* dyndbg) {
    ULONG read;

    // 读取第一个链表节点
    struct list_head head;
    if (!ExtReadMemory(ddebug_tables_addr, &head, sizeof(head), &read) ||
        read != sizeof(head)) {
        dprintf("WARNING: Failed to read ddebug_tables at 0x%I64x\n", ddebug_tables_addr);
        return false;
    }

    // 遍历链表
    ULONG64 current_list_node = (ULONG64)head.next;

    // 检查是否为空链表或无效指针
    if (current_list_node == ddebug_tables_addr || current_list_node == NULL) {
        dprintf("ddebug_tables list is empty\n");
        return true;
    }

    while (current_list_node != NULL && current_list_node != ddebug_tables_addr) {
        // 计算ddebug_table结构体地址 - 链表节点就是结构体的第一个字段
        ULONG64 table_addr = current_list_node;

        // 处理当前ddebug_table
        if (!dyndbg->process_ddebug_table_impl(table_addr)) {
            dprintf("WARNING: Failed to process ddebug_table at 0x%I64x\n", table_addr);
        }

        // 检查是否应该停止遍历(早期退出优化)
        if (dyndbg->should_stop_traversal()) {
            dprintf("Found target module, stopping traversal\n");
            break;
        }

        // 移动到下一个节点
        struct list_head next_list;
        if (!ExtReadMemory(current_list_node, &next_list, sizeof(next_list), &read) ||
            read != sizeof(next_list)) {
            dprintf("WARNING: Failed to read next list entry at 0x%I64x, stopping traversal\n", current_list_node);
            break;
        }

        ULONG64 next_addr = (ULONG64)next_list.next;

        // 检查指针有效性
        if (next_addr == 0 || next_addr == current_list_node) {
            dprintf("Reached end of list (next=0x%I64x)\n", next_addr);
            break;
        }

        current_list_node = next_addr;
    }

    dprintf("Finished processing ddebug_tables\n");
    return true;
}

/**
 * 执行ddebug查询
 */
void execute_ddebug_query(const ddebug_query* query) {
    if (!query) {
        return;
    }

    dprintf("Executing ddebug query:\n");

    if (query->modname) {
        dprintf("  Module: %s\n", query->modname);
    }
    if (query->filename) {
        dprintf("  File: %s\n", query->filename);
    }
    if (query->function) {
        dprintf("  Function: %s\n", query->function);
    }
    if (query->format) {
        dprintf("  Format: %s\n", query->format);
    }
    if (query->class_name) {
        dprintf("  Class: %s\n", query->class_name);
    }
    if (query->lineno > 0) {
        dprintf("  Line: %u\n", query->lineno);
    }

    if (query->has_flags_op) {
        dprintf("  Flag modifiers:\n");
        dprintf("    flags: 0x%x\n", query->modifiers.flags);
        dprintf("    mask:  0x%x\n", query->modifiers.mask);

        // 显示标志位含义
        struct flagsbuf fb;
        char* flags_desc = ddebug_describe_flags(query->modifiers.flags, &fb);
        dprintf("    description: %s\n", flags_desc);


        // 获取ddebug_tables全局变量地址
        ULONG64 ddebug_tables_addr = 0;
        if (!GetExpressionEx("lk!ddebug_tables", &ddebug_tables_addr, NULL)) {
            dprintf("ERROR: Failed to get address of ddebug_tables\n");
            return;
        }

        // 创建DynDbg实例并设置为更新模式
        DynDbg dyndbg;
        dyndbg.set_query_mode(false, query);  // 设置为更新模式

        dprintf("\nSearching and updating matching _ddebug entries...\n");

        // 遍历ddebug_tables链表
        if (!traverse_ddebug_tables(ddebug_tables_addr, &dyndbg)) {
            dprintf("ERROR: Failed to traverse ddebug_tables\n");
        }

        int total_updated = dyndbg.get_updated_count();
        if (total_updated > 0) {
            dprintf("\nSUCCESS: Updated %d _ddebug entries\n", total_updated);
        }
        else {
            dprintf("\nNo matching _ddebug entries found or updated\n");
        }
    }
    else {
        // 如果没有标志位操作,只是查询显示
        dprintf("\nQuery mode: No flags operation specified, use traverse command to view entries\n");
    }

    dprintf("\n");
}

/**
 * 处理无参数情况的查询显示
 */
void handle_no_args_query(DynDbg* dyndbg) {
    // 设置为查询模式
    dyndbg->set_query_mode(true, nullptr);

    // 获取ddebug_tables全局变量地址
    ULONG64 ddebug_tables_addr = 0;
    if (!GetExpressionEx("lk!ddebug_tables", &ddebug_tables_addr, NULL)) {
        dprintf("ERROR: Failed to get address of ddebug_tables\n");
        return;
    }

    dprintf("ddebug_tables found at address: 0x%I64x\n", ddebug_tables_addr);

    // 遍历ddebug_tables链表
    if (!traverse_ddebug_tables(ddebug_tables_addr, dyndbg)) {
        dprintf("ERROR: Failed to traverse ddebug_tables\n");
    }
}

/**
 * 处理带参数的命令解析和执行
 */
 /**
  * 显示用法说明
  */
static void show_usage() {
    dprintf("Linux Kernel Dynamic Debug Commands:\n");
    dprintf("  !ndx.dyndbg                          - Display all dynamic debug entries\n");
    dprintf("  !ndx.dyndbg -m <module>              - Filter by module name\n");
    dprintf("  !ndx.dyndbg -s <file>                - Filter by source file name\n");
    dprintf("  !ndx.dyndbg -f <function>            - Filter by function name\n");
    dprintf("  !ndx.dyndbg -t <format>              - Filter by format string\n");
    dprintf("  !ndx.dyndbg -l <line>                - Filter by line number\n");
    dprintf("  !ndx.dyndbg -c <class>               - Filter by class name\n");
    dprintf("  !ndx.dyndbg -h, --help, ?            - Show this help information\n");
    dprintf("\n");
    dprintf("Flag operations:\n");
    dprintf("  +p  - Enable printing\n");
    dprintf("  -p  - Disable printing\n");
    dprintf("  +m  - Include module name\n");
    dprintf("  +f  - Include function name\n");
    dprintf("  +l  - Include line number\n");
    dprintf("  +t  - Include thread ID\n");
    dprintf("\n");
    dprintf("Examples:\n");
    dprintf("  !ndx.dyndbg -m ext4 +p               - Enable debug printing for ext4 module\n");
    dprintf("  !ndx.dyndbg -m usb -p                - Disable printing for usb module\n");
}

/**
 * 检查是否为帮助命令
 */
bool is_help_command(const char* args) {
    if (!args) return false;

    // 跳过前导空格
    while (*args == ' ') args++;

    return (strcmp(args, "-h") == 0 ||
        strcmp(args, "-help") == 0 ||
        strcmp(args, "?") == 0);
}

void handle_args_command(const char* args) {
    ddebug_query query;

    if (parse_ddebug_command(args, &query)) {
        execute_ddebug_query(&query);
        free_ddebug_query(&query);
    }
    else {
        dprintf("ERROR: Failed to parse command\n");
    }
}


DECLARE_API(dyndbg) {
    // 检查是否为帮助命令
    if (is_help_command(args)) {
        show_usage();
        return;
    }

    DynDbg dyndbg;
    if (!args || !*args) {
        // 无参数时显示所有符号
        handle_no_args_query(&dyndbg);
    }
    else {
        // 有参数时解析并执行命令
        handle_args_command(args);
    }
}

4. 实例测试

!ndx.dyndbg -m configfs +p

作者:郭建程  创建时间:2025-09-22 13:47
最后编辑:郭建程  更新时间:2025-09-22 20:17