您的位置:首页 > 财经 > 产业 > 一个好的网站需要具备什么_济宁网站建设优化_无锡网站关键词推广_百度关键词价格计算

一个好的网站需要具备什么_济宁网站建设优化_无锡网站关键词推广_百度关键词价格计算

2025/3/18 23:02:45 来源:https://blog.csdn.net/h_b__k/article/details/146267447  浏览:    关键词:一个好的网站需要具备什么_济宁网站建设优化_无锡网站关键词推广_百度关键词价格计算
一个好的网站需要具备什么_济宁网站建设优化_无锡网站关键词推广_百度关键词价格计算

目录

一、基础介绍

二、PTRACE_TRACE 实现原理

三、代码实现

四、总结


 (代码:linux 6.3.1,架构:arm64)

One look is worth a thousand words.  —— Tess Flanders

一、基础介绍

        GDB(GNU Debugger)是 Linux 系统中功能强大的调试工具,用于调试 C、C++ 等编程语言编写的程序。GDB 支持两种主要的调试方式:"gdb主动加载被调试程序""gdb通过 attach 调试正在运行的程序"。这两种方式各有特点,适用于不同的调试场景。

        1)在 主动加载被调试程序 的方式中:GDB 通过 fork 和 exec 系统调用启动目标程序,并使用 ptrace 对其进行控制。这种方式适用于从头开始调试程序,开发者可以在程序启动时设置断点、单步执行或观察变量的初始状态。

        2)在 通过 attach 调试正在运行的程序 的方式中:GDB 通过 ptrace 附加到目标进程的 PID,直接接管其执行流程。这种方式适用于调试已经运行的程序,尤其是当程序出现崩溃、死锁或性能问题时,开发者可以实时分析程序的状态、调用栈和内存信息。

        两种调试方式的对比:

二、PTRACE_TRACE 实现原理

        以上就是 gdb 加载“被调试程序”启动阶段时的完整实现流程:

        1)gdb 调用 fork 创建子进程,用作后续的被调试程序,fork执行完毕后,gdb就调用wait系统调用等待在子进程上;

        2)子进程调用ptrace系统调用,请求类型为PTRACE_TRACEME,在内核中给子进程的task_struct对象置上PT_PTRACED标志;

        3)子进程调用exec,加载被调试程序的ELF文件;

        4)内核中调用 load_elf_binary 完成ELF加载工作;

        5)在内核的 exec 末期,发现自身置位了PT_PTRACED标志,于是调用ptrace_notify,给子进程自身发送一个SIGTRAP信号用于后续将子进程挂起

        6)子进程exec系统调用执行完毕后,在返回用户态前夕检查信号,发现自身有一个SIGTRAP信号需要处理,于是走信号处理流程

        7)子进程在内核的信号处理流程中,发送SIGCHLD信号给父进程gdb,并唤醒父进程gdb,同时将自身挂起;

        8)gdb被唤醒后,控制权交给用户,用户可以对被调试程序进行一系列操作(如:打断点、观察点等);

        9)用户操作完毕后,输入 continue指令,让目标程序继续运行。该指令实际会调用ptrace(PTRACE_CONT) 系统调用,在内核中该系统调用会将子进程唤醒;

        10)子进程被唤醒后,重新返回到用户态,开始执行第一条指令!

三、代码实现

1、gdb 加载 被调试程序

start_command {run_command_1 {run_target->create_inferior (exec_file, current_inferior ()->args (),current_inferior ()->environment.envp (), from_tty){fork_inferior(exec_file, allargs, env, void (*traceme_fun) () = gnu_ptrace_me, NULL, NULL, NULL, NULL) {pid = fork ()if (pid == 0) {					/* 子进程(被调试程序) */(*traceme_fun) ()A.K.Agnu_ptrace_me {ptrace (PTRACE_TRACEME)}execvp (argv[0], &argv[0])	// 加载被调试程序ELF}return pid	/* 父进程(GDB): 返回子进程pid */}...}}
}

2、PTRACE_TRACEME 内核实现

SYSCALL_DEFINE4(ptrace, long, request, long, pid, unsigned long, addr,unsigned long, data)
{if (request == PTRACE_TRACEME) {ptrace_traceme() {write_lock_irq(&tasklist_lock)if (!current->ptrace) {ret = security_ptrace_traceme(struct task_struct *parent = current->parent) {return cap_ptrace_traceme(parent)}if (!ret && !(current->real_parent->flags & PF_EXITING)) {current->ptrace = PT_PTRACED				// <<<<<<  子进程标记自己处于“PTRACED状态”  <<<<<<ptrace_link(current, current->real_parent)}}write_unlock_irq(&tasklist_lock)}}...
}

3、PTRACE_CONT 内核实现

ptrace_request(struct task_struct *child, long request, unsigned long addr, unsigned long data) {switch (request) {case PTRACE_CONT:return ptrace_resume(child, request, data) {... 	/* PTRACE跟踪syscall、单步调试等处理 */spin_lock_irq(&child->sighand->siglock)child->exit_code = datachild->jobctl &= ~JOBCTL_TRACEDwake_up_state(child, __TASK_TRACED) {return try_to_wake_up(p, state, 0)		// <<<<< 尝试唤醒被调试程序 <<<<<}spin_unlock_irq(&child->sighand->siglock)}}
}

4、内核 exec执行完毕后,返回用户态前夕,发送SIGCHLD给父进程gdb

// gdb通过fork创建出来的子进程, 调用exec加载被调试程序, 并给自己发送SIGTRAP信号
SYSCALL_DEFINE3(execve,const char __user *, filename,const char __user *const __user *, argv,const char __user *const __user *, envp)
{do_execvedo_execveat_commonbprm_execveexec_binprm {search_binary_handler {list_for_each_entry(fmt, &formats, lh) {retval = fmt->load_binary(bprm)		// <<<<< 加载ELF程序 主体函数 <<<<<}}### 给自身发送SIGTRAP信号, 在exec系统调用执行完毕返回用户态前夕, 处理该信号ptrace_event(PTRACE_EVENT_EXEC, old_vpid) {if ((current->ptrace & (PT_PTRACED|PT_SEIZED)) == PT_PTRACED)send_sig(SIGTRAP, current, 0)}}
}// 子进程exec执行完毕返回用户态前夕, 处理自身的SIGTRAP信号, 发送信号给GDB, 并将其唤醒, 随后自身挂起
exit_to_user_mode(regs) {prepare_exit_to_user_modelocal_daif_maskdo_notify_resume {if (thread_flags & (_TIF_SIGPENDING | _TIF_NOTIFY_SIGNAL))do_signal {get_signalptrace_signalptrace_stop(exit_code = signo, why = CLD_TRAPPED, 0, info)	/* Stop tracee itself, and notify parent tracer */{current->last_siginfo = infocurrent->exit_code = exit_codedo_notify_parent_cldstop(current, true, why) {info.si_signo  = SIGCHLDinfo.si_code   = whyinfo.si_status = tsk->exit_code & 0x7fsend_signal_locked(SIGCHLD, &info, parent, PIDTYPE_TGID)	// <<<<<< 发送信号给父进程GDB__wake_up_parent(tsk, parent)		// <<<<<< 唤醒父进程GDB}schedule()		// <<<<<< 被调试程序自身挂起}}}
}

四、总结

        gdb加载 “被调试程序” 进行调试的模式,主要依赖 PTRACE_TRACEME请求类型的ptrace系统调用,给子进程置上ptraced标记,后续子进程调用exec加载被调试程序ELF时给自己发送一个SIGTRAP信号,最后exec系统调用执行完毕并返回用户态前夕,在信号处理流程中,将自身挂起并唤醒GDB,让用户可以接管GDB串口,对被调试程序进行一系列调试操作。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com