命令字:!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, ¤t_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, ¤t_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 20:17