/usr/include/bits/dirent.h学习

本文解析了Linux系统中用于目录操作的头文件dirent.h及其内部结构体定义,并探讨了__ino_t等类型的含义及其与大文件操作相关的宏定义。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

看书遇到了#include<dirent.h>,/usr/include/目录下找到了两个,dirent.h和bits/dirent.h,第一个用到了第二个头文件,而且第二个简单,先学习以下。

/bits/dirent.h中定义了两个结构体:

文件中还有几个宏定义,没看明白,我不觉得很快会用到。

除此之外,仍有无法理解的语句。

__USE_LARGEFILE64与__USE_FILE_OFFSET64:该宏定义用来操作大文件的时候使用,有关的文章可以看这一篇:http://blog.youkuaiyun.com/tellyouatruth/article/details/5747543,我没有定义,所以用到的就是第一个。

 __ino_t:该类型是什么类型?一步一步查找下去:

在/usr/include/bits/types.h 中,


不过后面的注释搞不懂:file serial numbers,也没有查到是什么意思,先放一放。

这句中的__STD_TYPE也在/usr/include/bits/types.h定义:

语句中的__INO_T_TYPE定义 在/usr/inlcude/bits/typesizes.h:

而__SYSCALL_ULONG_TYPE也在同一个文件中:

至于__UQUAD_TYPE,在第三张截图中已经给出了,指的是无符号长整型。我的系统是x86_64的centos7,无符号长整型是8Byte长。那么 __ino_t就是无符号长整型。

同样地,找到__off_t是有符号长整型。

#define _GNU_SOURCE #include <sys/ptrace.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <elf.h> #include <sys/uio.h> #include <sys/stat.h> #include <dirent.h> #include <asm/ptrace.h> #include <android/log.h> // Android日志支持 // 修复1: 避免结构体重定义 #ifndef USER_HWDEBUG_STATE_DEFINED #define USER_HWDEBUG_STATE_DEFINED // ARM64硬件调试寄存器定义 #ifndef NT_ARM_HW_BREAK #define NT_ARM_HW_BREAK 0x402 // 执行断点寄存器集 #endif #ifndef NT_ARM_HW_WATCH #define NT_ARM_HW_WATCH 0x403 // 观察点寄存器集 #endif // ARM64硬件调试状态结构体 struct user_hwdebug_state { uint32_t dbg_info; // 调试信息字段 uint32_t pad; // 填充对齐 struct { uint64_t addr; // 断点地址寄存器 uint64_t ctrl; // 控制寄存器 } dbg_regs[16]; // 最大16个硬件断点槽位 }; #endif // 获取进程的所有线程ID int get_threads(pid_t pid, pid_t *threads, int max_threads) { char path[64]; int count = 0; snprintf(path, sizeof(path), "/proc/%d/task", pid); DIR *dir = opendir(path); if (!dir) { __android_log_print(ANDROID_LOG_ERROR, "HWBP", "打开/proc失败: %s", strerror(errno)); return 0; } struct dirent *entry; while ((entry = readdir(dir)) != NULL && count < max_threads) { if (entry->d_type == DT_DIR && strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) { threads[count++] = atoi(entry->d_name); } } closedir(dir); return count; } // 附加到目标进程及其所有线程 bool attach_to_process(pid_t pid) { // 附加主进程 if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) { __android_log_print(ANDROID_LOG_ERROR, "HWBP", "附加主进程失败: %s", strerror(errno)); return false; } // 等待主进程停止 int status; if (waitpid(pid, &status, 0) < 0 || !WIFSTOPPED(status)) { __android_log_print(ANDROID_LOG_ERROR, "HWBP", "等待主进程失败"); return false; } // 获取所有线程 pid_t threads[64]; int thread_count = get_threads(pid, threads, 64); if (thread_count == 0) { __android_log_print(ANDROID_LOG_WARN, "HWBP", "未找到任何线程"); return false; } // 附加所有线程 for (int i = 0; i < thread_count; i++) { pid_t tid = threads[i]; if (tid == pid) continue; // 跳过主线程 if (ptrace(PTRACE_ATTACH, tid, NULL, NULL) < 0) { __android_log_print(ANDROID_LOG_ERROR, "HWBP", "附加线程%d失败: %s", tid, strerror(errno)); continue; } if (waitpid(tid, &status, 0) < 0 || !WIFSTOPPED(status)) { __android_log_print(ANDROID_LOG_ERROR, "HWBP", "等待线程%d失败", tid); ptrace(PTRACE_DETACH, tid, NULL, NULL); continue; } __android_log_print(ANDROID_LOG_INFO, "HWBP", "已附加线程: %d", tid); } return true; } // 设置ARM64硬件断点 bool set_hw_breakpoint(pid_t tid, uintptr_t addr, int len, int type) { // 选择寄存器集类型 int nt_type = (type == 0) ? NT_ARM_HW_BREAK : NT_ARM_HW_WATCH; struct user_hwdebug_state dbg_regs; struct iovec iov = { .iov_base = &dbg_regs, .iov_len = sizeof(dbg_regs) }; // 获取当前调试寄存器状态 if (ptrace(PTRACE_GETREGSET, tid, nt_type, &iov) < 0) { __android_log_print(ANDROID_LOG_ERROR, "HWBP", "获取寄存器集失败: %s", strerror(errno)); return false; } // 查找空闲断点槽位 int slot = -1; for (int i = 0; i < 16; i++) { if (dbg_regs.dbg_regs[i].addr == 0) { slot = i; break; } } if (slot == -1) { __android_log_print(ANDROID_LOG_ERROR, "HWBP", "线程%d无可用断点槽位", tid); return false; } // 设置控制寄存器值 uint64_t ctrl_value = 0; if (type == 0) { // 执行断点 // 启用位(bit0) + 用户空间权限(EL0, bits[9:8]=0b01) ctrl_value = (1 << 0) | (0b01 << 8); } else { // 观察点 // 计算BAS掩码 (字节选择) uint64_t bas = 0; switch (len) { case 1: bas = 0x1; break; // 1字节: 0b0001 case 2: bas = 0x3; break; // 2字节: 0b0011 case 4: bas = 0xF; break; // 4字节: 0b1111 case 8: bas = 0xFF; break; // 8字节: 0b11111111 default: __android_log_print(ANDROID_LOG_ERROR, "HWBP", "无效长度%d,使用4字节", len); bas = 0xF; } // 基础设置 ctrl_value = (1 << 0) | // 启用 (0b01 << 8); // 用户空间(EL0) // 设置访问类型 if (type == 1) { // 读 ctrl_value |= (0b01 << 3); // Load } else if (type == 2) { // 写 ctrl_value |= (0b10 << 3); // Store } else if (type == 3) { // 读写 ctrl_value |= (0b11 << 3); // Load/Store } // 设置长度(BAS) ctrl_value |= (bas << 16); // BAS位置[23:16] } // 设置断点地址和控制值 dbg_regs.dbg_regs[slot].addr = addr; dbg_regs.dbg_regs[slot].ctrl = ctrl_value; // 应用设置到目标线程 if (ptrace(PTRACE_SETREGSET, tid, nt_type, &iov) < 0) { __android_log_print(ANDROID_LOG_ERROR, "HWBP", "设置寄存器集失败: %s", strerror(errno)); return false; } __android_log_print(ANDROID_LOG_INFO, "HWBP", "线程%d: 地址=0x%llx, 类型=%s, 长度=%d字节", tid, (unsigned long long)addr, type == 0 ? "执行" : type == 1 ? "读" : type == 2 ? "写" : "读写", len); return true; } // 主调试函数 void debug_process(pid_t target_pid, uintptr_t bp_addr, int bp_type, int bp_len) { // 附加到目标进程 if (!attach_to_process(target_pid)) { __android_log_print(ANDROID_LOG_ERROR, "HWBP", "无法附加到进程%d", target_pid); return; } // 获取所有线程 pid_t threads[64]; int thread_count = get_threads(target_pid, threads, 64); // 为所有线程设置断点 for (int i = 0; i < thread_count; i++) { if (!set_hw_breakpoint(threads[i], bp_addr, bp_len, bp_type)) { __android_log_print(ANDROID_LOG_WARN, "HWBP", "线程%d断点设置失败", threads[i]); } } // 恢复进程执行 for (int i = 0; i < thread_count; i++) { ptrace(PTRACE_CONT, threads[i], NULL, NULL); } __android_log_print(ANDROID_LOG_INFO, "HWBP", "进程恢复执行"); // 等待断点触发 int status; pid_t hit_tid = waitpid(-1, &status, 0); if (hit_tid > 0 && WIFSTOPPED(status)) { __android_log_print(ANDROID_LOG_INFO, "HWBP", "断点命中! 线程ID=%d", hit_tid); // 获取寄存器状态 struct user_pt_regs regs; struct iovec iov = { .iov_base = &regs, .iov_len = sizeof(regs) }; if (ptrace(PTRACE_GETREGSET, hit_tid, NT_PRSTATUS, &iov) == 0) { __android_log_print(ANDROID_LOG_INFO, "HWBP", "PC=0x%llx", (unsigned long long)regs.pc); __android_log_print(ANDROID_LOG_INFO, "HWBP", "LR=0x%llx", (unsigned long long)regs.regs[30]); } } // 清理并分离 for (int i = 0; i < thread_count; i++) { ptrace(PTRACE_DETACH, threads[i], NULL, NULL); } __android_log_print(ANDROID_LOG_INFO, "HWBP", "调试会话结束"); } // JNI入口函数 JNIEXPORT void JNICALL Java_com_example_debugtool_Debugger_nativeSetHardwareBreakpoint( JNIEnv *env, jobject thiz, jint pid, jlong address, jint type, jint length) { // 检查权限 if (geteuid() != 0) { __android_log_print(ANDROID_LOG_ERROR, "HWBP", "需要root权限"); return; } // 启动调试 debug_process((pid_t)pid, (uintptr_t)address, type, length); }报错问题:Android NDK: src/ptrace断点.cpp.bak [arm64-v8a] Compile++ : 无痕hook.sh <= ptrace断点.cpp jni/src/ptrace断点.cpp:30:8: error: redefinition of 'user_hwdebug_state' struct user_hwdebug_state { ^ /data/data/com.aide.ui.mgai/no_backup/ndksupport-1710240003/android-ndk-aide/sysroot/usr/include/aarch64-linux-android/asm/ptrace.h:61:8: note: previous definition is here struct user_hwdebug_state { ^ jni/src/ptrace断点.cpp:240:1: error: unknown type name 'JNIEXPORT' JNIEXPORT void JNICALL ^ jni/src/ptrace断点.cpp:240:11: error: expected unqualified-id JNIEXPORT void JNICALL ^ 3 errors generated. make: *** [/data/data/com.aide.ui.mgai/no_backup/ndksupport-1710240003/android-ndk-aide/build/core/build-binary.mk:530: obj/local/arm64-v8a/objs/无痕hook.sh/src/ptrace 断点.o] Error 1帮我彻底修复好完整发给我
07-14
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值