命令字:!ndx.sysdevices
用法描述
用于 查询系统设备列表,设备名、内存地址定位目标设备
适用于内核设备模型排查、驱动绑定验证、设备资源分析等场景。
支持的命令行参数:
-n 按设备名筛选设备,支持通配符(*)匹配
-a 按设备的内存地址精确查询设备
-h / –help / ? 显示命令帮助文档(含参数说明、示例)
开发过程
1. 找到关键全局变量
关键全局变量 | 作用 |
---|---|
devices_kset | 统一管理系统中所有已注册的设备对象 |
使用dt命令查看,确保存在这个kset
2. 相关内核实现和数据结构
device_initialize初始化设备结构体(struct device)的核心成员
device_add将设备添加到系统中
device_initialize指定了对象的所属集合
kobject_add(&dev->kobj, dev->kobj.parent, NULL)
将kobject注册到内核对象系统中,并在 sysfs 文件系统中创建对应的目录,这里第二个参数用于指定父目录
kset
struct kset {
struct list_head list; // 链表头:串联子kobject,支持批量遍历
spinlock_t list_lock;
struct kobject kobj; // 内嵌kobj:实现sysfs映射与层级管理
const struct kset_uevent_ops *uevent_ops;
} __randomize_layout;
kobject
struct kobject {
const char *name; // 名称:标识kobject(如对应sysfs目录名)
struct list_head entry; // 链表项:接入父kset的list链表,实现层级串联
struct kobject *parent; // 父kobj:指定上层kobject,构成sysfs目录层级
struct kset *kset; // 所属kset:关联到管理它的kset
const struct kobj_type *ktype;
struct kernfs_node *sd; // sysfs节点:映射到sysfs的目录/文件项
struct kref kref; // 引用计数:管理kobject生命周期,防止提前释放
// 以下为状态位(1bit):
unsigned int state_initialized:1;
unsigned int state_in_sysfs:1;
unsigned int state_add_uevent_sent:1;
unsigned int state_remove_uevent_sent:1;
unsigned int uevent_suppress:1;
};
device
dt lk!device
+0x000 kobj : kobject
+0x040 parent : Ptr64 device
+0x048 p : Ptr64 device_private
+0x050 init_name : Ptr64 Char
+0x058 type : Ptr64 device_type
+0x060 bus : Ptr64 bus_type
+0x068 driver : Ptr64 device_driver
+0x070 platform_data : Ptr64 Void
+0x078 driver_data : Ptr64 Void
+0x080 mutex : mutex
+0x0b8 links : dev_links_info
+0x0f0 power : dev_pm_info
+0x260 pm_domain : Ptr64 dev_pm_domain
+0x268 em_pd : Ptr64 em_perf_domain
+0x270 pins : Ptr64 dev_pin_info
+0x278 msi : dev_msi_info
+0x288 dma_ops : Ptr64 dma_map_ops
+0x290 dma_mask : Ptr64 Uint8B
+0x298 coherent_dma_mask : Uint8B
+0x2a0 bus_dma_limit : Uint8B
+0x2a8 dma_range_map : Ptr64 bus_dma_region
+0x2b0 dma_parms : Ptr64 device_dma_parameters
+0x2b8 dma_pools : list_head
+0x2c8 dma_mem : Ptr64 dma_coherent_mem
+0x2d0 cma_area : Ptr64 cma
+0x2d8 dma_io_tlb_mem : Ptr64 io_tlb_mem
+0x2e0 archdata : dev_archdata
+0x2e0 of_node : Ptr64 device_node
+0x2e8 fwnode : Ptr64 fwnode_handle
+0x2f0 devt : Uint4B
+0x2f4 id : Uint4B
+0x2f8 devres_lock : spinlock
+0x310 devres_head : list_head
+0x320 class : Ptr64 class
+0x328 groups : Ptr64 Ptr64 attribute_group
+0x330 release : Ptr64
+0x338 iommu_group : Ptr64 iommu_group
+0x340 iommu : Ptr64 dev_iommu
+0x348 physical_location : Ptr64 device_physical_location
+0x350 removable : device_removable
+0x354 offline_disabled : Pos 6816, 1 Bit
+0x354 offline : Pos 6817, 1 Bit
+0x354 of_node_reused : Pos 6818, 1 Bit
+0x354 state_synced : Pos 6819, 1 Bit
+0x354 can_match : Pos 6820, 1 Bit
+0x354 dma_coherent : Pos 6821, 1 Bit
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 "sysdevices.h"
SysDevices::SysDevices() {
// 初始化结构体偏移量
kobject_offsets.initialized = false;
kset_offsets.initialized = false;
device_offsets.initialized = false;
init_kobject_offsets();
init_kset_offsets();
init_device_offsets();
}
// 初始化kobject结构体偏移量
bool SysDevices::init_kobject_offsets() {
if (kobject_offsets.initialized) {
return true;
}
memset(&kobject_offsets, 0, sizeof(kobject_offsets));
if (GetFieldOffset("kobject", "name", &kobject_offsets.name_offset) != 0) {
dprintf("WARNING: Failed to get kobject.name offset\n");
return false;
}
if (GetFieldOffset("kobject", "entry", &kobject_offsets.entry_offset) != 0) {
dprintf("WARNING: Failed to get kobject.entry offset\n");
return false;
}
kobject_offsets.initialized = true;
return true;
}
// 初始化kset结构体偏移量
bool SysDevices::init_kset_offsets() {
if (kset_offsets.initialized) {
return true;
}
memset(&kset_offsets, 0, sizeof(kset_offsets));
if (GetFieldOffset("kset", "list", &kset_offsets.list_offset) != 0) {
dprintf("WARNING: Failed to get kset.list offset\n");
return false;
}
kset_offsets.initialized = true;
return true;
}
// 初始化device结构体偏移量
bool SysDevices::init_device_offsets() {
if (device_offsets.initialized) {
return true;
}
memset(&device_offsets, 0, sizeof(device_offsets));
if (GetFieldOffset("device", "kobj", &device_offsets.kobj_offset) != 0) {
dprintf("WARNING: Failed to get device.kobj offset\n");
return false;
}
device_offsets.initialized = true;
return true;
}
// 设备kobject处理上下文结构
struct DeviceKobjectContext {
const KobjectOffsets* offsets;
const DeviceOffsets* device_offsets;
ULONG device_count; // 统计设备数量
const DeviceFilterParams* filter; // 过滤参数
SysDevices* sys_devices; // SysDevices实例指针
};
// 按名称查找设备的上下文结构
// 设备匹配结果结构体
struct DeviceMatchResult {
ULONG64 device_addr;
char device_name[64];
};
struct DeviceSearchContext {
const char* search_name;
bool found;
bool is_exact_match; // 是否为精确匹配(无通配符)
std::vector<DeviceMatchResult> matches; // 存储所有匹配的设备
const KobjectOffsets* offsets;
const DeviceOffsets* device_offsets;
};
// 按名称查找设备的回调函数
static bool search_device_by_name(ULONG64 kobject_addr, void* context) {
ULONG read;
DeviceSearchContext* search_ctx = static_cast<DeviceSearchContext*>(context);
// 计算device结构体地址
ULONG64 device_addr = kobject_addr - search_ctx->device_offsets->kobj_offset;
// 读取kobject名称指针
char* name_ptr = NULL;
if (!ExtReadMemory(kobject_addr + search_ctx->offsets->name_offset, &name_ptr, sizeof(name_ptr), &read) ||
read != sizeof(name_ptr)) {
return true; // 继续查找
}
// 读取名称字符串
char name[64] = "<unknown>";
if (name_ptr != NULL) {
if (!ExtReadMemory((ULONG64)name_ptr, name, sizeof(name) - 1, &read)) {
return true; // 继续查找
}
else {
name[read < sizeof(name) - 1 ? read : sizeof(name) - 1] = '\0';
}
}
// 检查名称是否匹配(使用通配符匹配)
if (SysDevices::wildcard_match(name, search_ctx->search_name)) {
search_ctx->found = true;
// 添加匹配结果到列表
DeviceMatchResult match;
match.device_addr = device_addr;
strcpy_s(match.device_name, sizeof(match.device_name), name);
search_ctx->matches.push_back(match);
// 如果是精确匹配,找到第一个就停止
if (search_ctx->is_exact_match) {
return false; // 停止查找
}
}
return true; // 继续查找
}
// 按地址查找设备的上下文结构
struct DeviceAddressSearchContext {
ULONG64 search_addr;
bool found;
char device_name[64];
const KobjectOffsets* offsets;
const DeviceOffsets* device_offsets;
};
// 按地址查找设备的回调函数
static bool search_device_by_address(ULONG64 kobject_addr, void* context) {
ULONG read;
DeviceAddressSearchContext* search_ctx = static_cast<DeviceAddressSearchContext*>(context);
// 计算device结构体地址
ULONG64 device_addr = kobject_addr - search_ctx->device_offsets->kobj_offset;
// 检查地址是否匹配
if (device_addr == search_ctx->search_addr) {
// 读取kobject名称指针
char* name_ptr = NULL;
if (ExtReadMemory(kobject_addr + search_ctx->offsets->name_offset, &name_ptr, sizeof(name_ptr), &read) &&
read == sizeof(name_ptr) && name_ptr != NULL) {
// 读取名称字符串
if (ExtReadMemory((ULONG64)name_ptr, search_ctx->device_name, sizeof(search_ctx->device_name) - 1, &read)) {
search_ctx->device_name[read < sizeof(search_ctx->device_name) - 1 ? read : sizeof(search_ctx->device_name) - 1] = '\0';
}
else {
strcpy_s(search_ctx->device_name, sizeof(search_ctx->device_name), "<unknown>");
}
}
else {
strcpy_s(search_ctx->device_name, sizeof(search_ctx->device_name), "<unknown>");
}
search_ctx->found = true;
return false; // 找到了,停止查找
}
return true; // 继续查找
}
// 处理设备kobject的回调函数
static bool process_device_kobject(ULONG64 kobject_addr, void* context) {
ULONG read;
DeviceKobjectContext* dev_ctx = static_cast<DeviceKobjectContext*>(context);
// 计算device结构体地址
ULONG64 device_addr = kobject_addr - dev_ctx->device_offsets->kobj_offset;
// 读取kobject名称指针
char* name_ptr = NULL;
if (!ExtReadMemory(kobject_addr + dev_ctx->offsets->name_offset, &name_ptr, sizeof(name_ptr), &read) ||
read != sizeof(name_ptr)) {
dprintf("WARNING: Failed to read kobject name pointer at 0x%llx\n", kobject_addr);
return true;
}
// 读取名称字符串
char name[64] = "<unknown>";
if (name_ptr != NULL) {
if (!ExtReadMemory((ULONG64)name_ptr, name, sizeof(name) - 1, &read)) {
dprintf("WARNING: Failed to read kobject name at %p\n", (ULONG64)name_ptr);
}
else {
name[read < sizeof(name) - 1 ? read : sizeof(name) - 1] = '\0';
}
}
// 输出设备信息(包含device地址)
dprintf(" %-30s 0x%016llx\n", name, device_addr);
dev_ctx->device_count++;
return true;
}
// 链表遍历函数
bool SysDevices::traverse_generic_list(ULONG64 list_head_addr, const struct list_head& list_head,
ULONG list_offset, ListNodeProcessor processor, void* context) {
ULONG64 current_addr = (ULONG64)list_head.next;
ULONG read;
while (current_addr != list_head_addr) {
// 读取当前节点
struct list_head current_node;
if (!ExtReadMemory(current_addr, ¤t_node, sizeof(current_node), &read) ||
read != sizeof(current_node)) {
dprintf("WARNING: Failed to read list node at 0x%llx\n", current_addr);
break;
}
// 计算包含该链表节点的结构体地址
ULONG64 container_addr = current_addr - list_offset;
// 调用处理函数
if (!processor(container_addr, context)) {
break;
}
// 移动到下一个节点
current_addr = (ULONG64)current_node.next;
// 防止无限循环
if (current_addr == 0) {
break;
}
}
return true;
}
// 显示所有设备kobject
void SysDevices::list_all_devices(ULONG64 next_node_addr, struct list_head next_node) {
DeviceKobjectContext context;
context.offsets = &kobject_offsets;
context.device_offsets = &device_offsets;
context.device_count = 0;
dprintf("\nDevices:\n");
dprintf(" %-30s %s\n", "Name", "Device Address");
dprintf(" %-30s %s\n", "------------------------------", "----------------");
// 遍历设备链表
traverse_generic_list(next_node_addr, next_node, kobject_offsets.entry_offset,
process_device_kobject, &context);
dprintf("\nTotal devices: %lu\n", context.device_count);
}
// 按名称查找设备
bool SysDevices::query_device_by_name(const char* device_name, ULONG64 devices_kset_addr) {
ULONG read;
// 读取kset.list字段
ULONG64 kset_list_addr = devices_kset_addr + get_kset_offsets().list_offset;
// 读取链表头
struct list_head kset_list;
if (!ExtReadMemory(kset_list_addr, &kset_list, sizeof(kset_list), &read) ||
read != sizeof(kset_list)) {
dprintf("ERROR: Failed to read kset list head at 0x%llx\n", kset_list_addr);
return false;
}
// 判断是否为精确匹配(无通配符)
std::string pattern(device_name);
bool is_exact_match = (pattern.find('*') == std::string::npos);
// 设置查找上下文
DeviceSearchContext search_ctx;
search_ctx.search_name = device_name;
search_ctx.found = false;
search_ctx.is_exact_match = is_exact_match;
search_ctx.matches.clear();
search_ctx.offsets = &kobject_offsets;
search_ctx.device_offsets = &device_offsets;
// 读取kset_list.next指向的节点
ULONG64 next_node_addr = (ULONG64)kset_list.next;
struct list_head next_node;
if (!ExtReadMemory(next_node_addr, &next_node, sizeof(next_node), &read) ||
read != sizeof(next_node)) {
dprintf("ERROR: Failed to read next list node at 0x%llx\n", next_node_addr);
return false;
}
// 显示搜索提示信息
dprintf("Searching for device '%s', please wait...\n", device_name);
// 遍历设备链表查找
traverse_generic_list(next_node_addr, next_node, kobject_offsets.entry_offset,
search_device_by_name, &search_ctx);
if (search_ctx.found && !search_ctx.matches.empty()) {
if (is_exact_match) {
// 精确匹配,只显示第一个结果
const auto& match = search_ctx.matches[0];
dprintf("Device found:\n");
dprintf(" Name: %s\n", match.device_name);
dprintf(" Address: 0x%016llx\n", match.device_addr);
}
else {
// 通配符匹配,显示所有匹配的设备(表格格式)
dprintf("\nDevices:\n");
dprintf(" %-30s %s\n", "Name", "Device Address");
dprintf(" %-30s %s\n", "------------------------------", "----------------");
for (const auto& match : search_ctx.matches) {
dprintf(" %-30s 0x%016llx\n", match.device_name, match.device_addr);
}
dprintf("\nTotal: %zu device(s) matched pattern '%s'\n",
search_ctx.matches.size(), device_name);
}
return true;
}
else {
dprintf("Device '%s' not found\n", device_name);
return false;
}
}
// 按地址查找设备
bool SysDevices::query_device_by_address(ULONG64 target_addr, ULONG64 devices_kset_addr) {
ULONG read;
// 读取kset.list字段
ULONG64 kset_list_addr = devices_kset_addr + get_kset_offsets().list_offset;
// 读取链表头
struct list_head kset_list;
if (!ExtReadMemory(kset_list_addr, &kset_list, sizeof(kset_list), &read) ||
read != sizeof(kset_list)) {
dprintf("ERROR: Failed to read kset list head at 0x%llx\n", kset_list_addr);
return false;
}
// 设置查找上下文
DeviceAddressSearchContext search_ctx;
search_ctx.search_addr = target_addr;
search_ctx.found = false;
search_ctx.offsets = &kobject_offsets;
search_ctx.device_offsets = &device_offsets;
// 读取kset_list.next指向的节点
ULONG64 next_node_addr = (ULONG64)kset_list.next;
struct list_head next_node;
if (!ExtReadMemory(next_node_addr, &next_node, sizeof(next_node), &read) ||
read != sizeof(next_node)) {
dprintf("ERROR: Failed to read next list node at 0x%llx\n", next_node_addr);
return false;
}
// 遍历设备链表查找
traverse_generic_list(next_node_addr, next_node, kobject_offsets.entry_offset,
search_device_by_address, &search_ctx);
if (search_ctx.found) {
dprintf("Device found:\n");
dprintf(" Name: %s\n", search_ctx.device_name);
dprintf(" Address: 0x%016llx\n", target_addr);
return true;
}
else {
dprintf("Device at address 0x%016llx not found\n", target_addr);
return false;
}
}
// 通配符匹配函数
bool SysDevices::wildcard_match(const char* text, const char* pattern) {
std::string text_str(text);
std::string pattern_str(pattern);
if (pattern_str.empty()) {
return text_str.empty();
}
// 检查是否包含通配符
if (pattern_str.find('*') == std::string::npos) {
// 没有通配符,精确匹配
return text_str == pattern_str;
}
// 处理特殊情况:只有一个*
if (pattern_str == "*") {
return true; // 匹配任何字符串
}
// 【重要】前后缀匹配:*abc* - 必须优先检查,避免被单独的前缀/后缀匹配拦截
if (pattern_str.front() == '*' && pattern_str.back() == '*') {
if (pattern_str.length() <= 2) {
return true; // ** 或 * 匹配任何字符串
}
std::string substring = pattern_str.substr(1, pattern_str.length() - 2);
return text_str.find(substring) != std::string::npos;
}
// 后缀匹配:*abc
if (pattern_str.front() == '*') {
std::string suffix = pattern_str.substr(1);
if (suffix.empty()) {
return true; // * 匹配任何字符串
}
if (text_str.length() < suffix.length()) {
return false;
}
return text_str.substr(text_str.length() - suffix.length()) == suffix;
}
// 前缀匹配:abc*
if (pattern_str.back() == '*') {
std::string prefix = pattern_str.substr(0, pattern_str.length() - 1);
if (prefix.empty()) {
return true; // * 匹配任何字符串
}
return text_str.substr(0, prefix.length()) == prefix;
}
// 精确匹配
return text_str == pattern_str;
}
// 显示使用帮助
static void show_usage() {
dprintf("Usage: !ndx.sysdevices [options]\n");
dprintf("Options:\n");
dprintf(" (no args) List all devices\n");
dprintf(" -n <name> Search device by name (supports wildcards)\n");
dprintf(" -a <address> Search device by address\n");
dprintf(" -h, --help, ? Show this help message\n");
dprintf("\nWildcard patterns for name search:\n");
dprintf(" * Match any string\n");
dprintf(" prefix* Match strings starting with 'prefix'\n");
dprintf(" *suffix Match strings ending with 'suffix'\n");
dprintf(" *substring* Match strings containing 'substring'\n");
dprintf("\nExamples:\n");
dprintf(" !ndx.sysdevices # List all devices\n");
dprintf(" !ndx.sysdevices -n \"cpu0\" # Search for device named 'cpu0'\n");
dprintf(" !ndx.sysdevices -n \"cpu*\" # Search for devices starting with 'cpu'\n");
dprintf(" !ndx.sysdevices -n \"*usb*\" # Search for devices containing 'usb'\n");
dprintf(" !ndx.sysdevices -a 0xffff888012345678 # Search for device at address\n");
}
// 检查是否为帮助命令
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;
}
// 解析和执行命令
bool SysDevices::parse_and_execute_command(const char* args, ULONG64 devices_kset_addr) {
if (!args || !*args) {
// 无参数时显示所有设备
ULONG read;
// 读取kset.list字段
ULONG64 kset_list_addr = devices_kset_addr + get_kset_offsets().list_offset;
// 读取链表头
struct list_head kset_list;
if (!ExtReadMemory(kset_list_addr, &kset_list, sizeof(kset_list), &read) ||
read != sizeof(kset_list)) {
dprintf("ERROR: Failed to read kset list head at 0x%llx\n", kset_list_addr);
return false;
}
// 读取kset_list.next指向的节点
ULONG64 next_node_addr = (ULONG64)kset_list.next;
struct list_head next_node;
if (!ExtReadMemory(next_node_addr, &next_node, sizeof(next_node), &read) ||
read != sizeof(next_node)) {
dprintf("ERROR: Failed to read next list node at 0x%llx\n", next_node_addr);
return false;
}
// 显示所有设备
list_all_devices(next_node_addr, next_node);
return true;
}
// 创建参数副本以避免修改原始字符串
char args_copy[256];
strncpy_s(args_copy, sizeof(args_copy), args, _TRUNCATE);
char* token = strtok(args_copy, " ");
if (!token) {
show_usage();
return false;
}
// 解析命令选项
if (_stricmp(token, "-n") == 0) {
// 按名称查询
char* device_name = strtok(nullptr, " ");
if (!device_name) {
dprintf("ERROR: Missing device name\n");
show_usage();
return false;
}
// 执行查询
return query_device_by_name(device_name, devices_kset_addr);
}
else if (_stricmp(token, "-a") == 0) {
// 按地址查询
char* addr_str = strtok(nullptr, " ");
if (!addr_str) {
dprintf("ERROR: Missing address\n");
show_usage();
return false;
}
// 解析地址
ULONG64 addr;
if (!GetExpressionEx(addr_str, &addr, NULL)) {
dprintf("ERROR: Invalid address format '%s'\n", addr_str);
show_usage();
return false;
}
// 执行查询
return query_device_by_address(addr, devices_kset_addr);
}
else if (_stricmp(token, "-h") == 0 || _stricmp(token, "--help") == 0 || _stricmp(token, "?") == 0) {
// 显示帮助信息
show_usage();
return true;
}
else {
dprintf("ERROR: Unknown option '%s'\n", token);
show_usage();
return false;
}
}
DECLARE_API(sysdevices) {
// 首先检查是否为帮助命令,如果是则直接显示帮助,无需初始化
if (is_help_command(args)) {
return;
}
ULONG64 devices_kset_addr = 0;
// 获取devices_kset全局变量的地址
if (!GetExpressionEx("lk!devices_kset", &devices_kset_addr, NULL)) {
dprintf("ERROR: Failed to get devices_kset address\n");
return;
}
dprintf("devices_kset address: 0x%llx\n", devices_kset_addr);
// 创建SysDevices实例
SysDevices sysDevices;
// 参数解析逻辑
sysDevices.parse_and_execute_command(args, devices_kset_addr);
}
4. 实例测试
!ndx.sysdevices
作者:郭建程 创建时间:2025-09-29 15:45
最后编辑:郭建程 更新时间:2025-10-13 16:46
最后编辑:郭建程 更新时间:2025-10-13 16:46