当前位置: 首页 > wzjs >正文

用ps切片做网站网站建设的所需解决的技术问题

用ps切片做网站,网站建设的所需解决的技术问题,干部网络培训平台,做酒类网站目录 一、gdb跟踪被调试程序的fork、pthread_create操作 二、实现原理 三、代码实现 四、总结 (代码:linux 6.3.1,架构:arm64) One look is worth a thousand words. —— Tess Flanders 相关链接: …

目录

一、gdb跟踪被调试程序的fork、pthread_create操作

二、实现原理

三、代码实现

四、总结


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

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

相关链接:

linux ptrace 图文详解(一)基础介绍

linux ptrace 图文详解(二) PTRACE_TRACEME 跟踪程序

linux ptrace 图文详解(三) PTRACE_ATTACH 跟踪程序

linux ptrace 图文详解(四) gdb设置软断点

linux ptrace 图文详解(五) gdb设置硬断点、观察点

linux ptrace 图文详解(六) gdb单步调试

linux ptrace 图文详解(七) gdb、strace跟踪系统调用

在开始之前,我们先思考几个问题:

1)gdb调试一个程序,该程序所创建的子进程、子线程,是否同样会被gdb跟踪?

2)若gdb可以跟踪被调试程序的子进程、子线程,这是如何实现的?gdb如何获取到子进程、子线程的信息?

3)gdb一定要跟踪被调试程序的子线程、子进程么?

一、gdb跟踪被调试程序的fork、pthread_create操作

        GDB 从 版本 7.0 开始支持用户显式控制是否监控被调试程序创建的子进程和子线程。以下是一些gdb控制调试子进程、子线程的一些常见指令:

        1)gdb控制子进程调试

                set follow-fork-mode <mode>

                mode选项:

                - parent(默认):仅调试父进程,子进程继续运行不受监控

                - child:切换到调试子进程,父进程继续运行

                set detach-on-fork <on/off>

                - on:分离非调试的进程(若选择跟踪子进程时,父进程会被分离)

                - off:同时调试父子进程(需配合inferior命令切换)

        2)gdb控制子线程调试

                set scheduler-locking <mode>

                mode选项:

                - off(默认):所有线程自由运行;

                - on:仅当前调试的线程运行,其他线程暂停;

                - setp:单步执行时仅当前线程运行(避免其他线程干扰);

        使用示例:

# 启动gdb设置调试模式
gdb ./test
(gdb) set follow-fork-mode child  # 跟踪子进程
(gdb) set detach-on-fork off      # 不分离父进程
(gdb) break child_function        # 在子进程函数设断点
(gdb) run# 切换进程
(gdb) info inferiorsNum  Description       Executable1    process 1234      ./test (父进程)2    process 1235      ./test (子进程)
(gdb) inferior 2  # 切换到子进程

二、实现原理

gdb跟踪被调试程序创建的子进程/子线程的原理如下:

        1)被调试程序(父进程)调用fork、pthread_create后,陷入内核的系统调用都是kernel_clone;

        2)为 子进程/子线程 创建对应的task_struct对象,并且dup相应的内核对象;

        3)子进程/子线程 的task_struct对象,继承父进程的ptrace字段(该字段的用途:控制当前进程的哪些行为需要被gdb接管,该字段通常是由gdb通过ptrace进行设置的);

        4)父进程 给 子进程/子线程 的task对象添加一个SIGSTOP信号,目的是让子进程/子线程被调度运行时将自己挂起;

        5)父进程通过wake_up_new_task 将 子进程/子线程 添加到就绪队列等待被调度运行;

        6)子进程/子线程被调度运行时,返回用户态前夕,检查是否存在pending信号,发现有SIGSTOP,于是将自己挂起,并通知gdb;

        7)父进程 将 子进程/子线程 的pid,记录到自己的ptrace_message字段中(后续gdb会来拿这个信息);

        8)父进程发现自己的task->ptrace字段包含了 PTRACE_EVENT_CLONE、PTRACE_EVENT_FORK,代表当前任务的fork、pthread_create动作需要通知gdb,于是调用ptrace_stop,通知父进程并将自己挂起;

        9)gdb被唤醒后,通过wait的status参数得知被调试程序执行了fork、pthread_create动作;

        10)gdb通过ptrace(PTRACE_GETEVENTMSG),陷入内核获取记录在父进程task->ptrace_message中的信息,该信息就是父进程创建的 子进程/子线程 的 pid;

        12)gdb 为 被调试程序创建的 子进程/子线程 创建对应的数据结构,记录在gdb中,至此gdb侧就掌握了被调试程序的所有子线程、子进程相关信息;

        13)最后,gdb通过ptrace(PTRACE_CONT)将被调试程序(父进程)、及其创建的 子进程/子线程 唤醒继续运行;

        14)父进程 以及其创建的 子进程/子线程 被调度继续运行;

三、代码实现

1、gdb为被调试程序设置对应的ptrace字段(告知子进程其哪些动作需要被gdb拦截)

// Case1
linux_process_target::post_create_inferiorlinux_enable_event_reportingsupported_ptrace_options = (PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACECLONE | PTRACE_O_TRACEFORK| PTRACE_O_TRACEVFORK | PTRACE_O_TRACEVFORKDONE | PTRACE_O_TRACEEXEC)options &= supported_ptrace_optionsptrace(PTRACE_SETOPTIONS, pid, ..., options)flags = task->ptraceflags &= ~(PTRACE_O_MASK << PT_OPT_FLAG_SHIFT)flags |= (options << PT_OPT_FLAG_SHIFT)task->ptrace = flags// Case2
linux_enable_event_reporting (pid_t pid, int options) {if (supported_ptrace_options == -1) {linux_check_ptrace_features() {supported_ptrace_options = (PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACECLONE | PTRACE_O_TRACEFORK| PTRACE_O_TRACEVFORK | PTRACE_O_TRACEVFORKDONE | PTRACE_O_TRACEEXEC)...}}/* We always want clone events. */options |= PTRACE_O_TRACECLONE/* Filter out unsupported options. */options &= supported_ptrace_optionsptrace(PTRACE_SETOPTIONS, pid, (PTRACE_TYPE_ARG3) 0, (PTRACE_TYPE_ARG4) (uintptr_t) options) {sys_ptrace(request, pid, addr, data) {ptrace_request(struct task_struct *child, long request, unsigned long addr, unsigned long data) {switch (request)case PTRACE_SETOPTIONS:ptrace_setoptions(child, data) {flags = child->ptraceflags &= ~(PTRACE_O_MASK << PT_OPT_FLAG_SHIFT)flags |= (data << PT_OPT_FLAG_SHIFT)			// 即: flag |= data << 3child->ptrace = flags							// <<<<<< 将 PTRACE_O_TRACEFORK 等event, 设置给目标任务task_struct->ptrace字段}}}}
}

2、父进程执行fork/pthread_create,在内核中的kernel_clone实现

SYSCALL_DEFINE0(fork) {kernel_clone(struct kernel_clone_args *args)int trace = 0u64 clone_flags = args->flags/* Determine whether and which event to report to ptracer. */if (!(clone_flags & CLONE_UNTRACED)) {if (clone_flags & CLONE_VFORK)trace = PTRACE_EVENT_VFORKelse if (args->exit_signal != SIGCHLD)				// pthread_createtrace = PTRACE_EVENT_CLONEelsetrace = PTRACE_EVENT_FORK/******** 判断current是否包含对应trace event *********/ret = ptrace_event_enabled(struct task_struct *task = current, int event = trace) {return task->ptrace & PT_EVENT_FLAG(event)}if (likely(!ret))	trace = 0}struct task_struct *p = copy_process(NULL, trace, NUMA_NO_NODE, args) {p = dup_task_struct(current, node)												// 为新创建的任务生成一个新的task_structptrace_init_task(p, bool ptrace = (clone_flags & CLONE_PTRACE) || trace)		// initialize ptrace state for a new childif (unlikely(ptrace) && current->ptrace)child->ptrace = current->ptrace				/* Set ptrace event to new child task's ptrace, which will be checked later */__ptrace_link(child, current->parent, current->ptracer_cred)sigaddset(&child->pending.signal, SIGSTOP)								// Add SIGSTOP to new task's pending.signal}wake_up_new_task(p)																	// new task will stop when go back to user space a.k.a do_signalif (unlikely(trace)) {	/* forking complete and child started to run, tell ptracer */ptrace_event_pid(event = trace, pid) {message = pid_nr_ns(pid, ns)			/* message: new task's pid. 保存在父进程的task_struct->ptrace_message中 */ptrace_event(event, message)if (unlikely(ptrace_event_enabled(current, event)))current->ptrace_message = messageptrace_notify(exit_code = (event << 8) | SIGTRAP)					// event: PTRACE_EVENT_FORK / PTRACE_EVENT_CLONE / PTRACE_EVENT_VFORKptrace_do_notify(SIGTRAP, exit_code, CLD_TRAPPED)ptrace_stop(exit_code, why, 1, &info)}}
}

3、gdb收集被调试程序fork/pthread_create创建的子进程/子线程信息

linux_process_target::wait_for_event_filtered {	// 3) *** gdb获取子线程/子进程 pid信息 ***/* Always pull all events out of the kernel */while (event_child == NULL) {ret = my_waitpid(wstatp)if (ret > 0) {linux_process_target::filter_event(int lwpid = ret, int wstat = *wstatp) {ret = linux_is_extended_waitstatus (wstat)							// 该函数用于check wait返回后的入参,是否有event事件, 即: PTRACE_EVENT_FORK、PTRACE_EVENT_CLONE 这类事件return (linux_ptrace_get_extended_event (wstat) != 0)return (wstat >> 16)if (WIFSTOPPED (wstat) && WSTOPSIG (wstat) == SIGTRAP && ret) {linux_process_target::handle_extended_wait {int event = linux_ptrace_get_extended_event (wstat)return (wstat >> 16)if ((event == PTRACE_EVENT_FORK) || (event == PTRACE_EVENT_VFORK) || (event == PTRACE_EVENT_CLONE)) {/* Get the pid of the new lwp. */ptrace (PTRACE_GETEVENTMSG, lwpid_of (event_thr), (PTRACE_TYPE_ARG3) 0, &new_pid)*(unsigned long *)data = child->ptrace_messageA.K.A*new_pid = child->ptrace_message				// 获取新的task的pid/* If we haven't already seen the new PID stop, wait for it now.  */if (!pull_pid_from_list (&stopped_pids, new_pid, &status)) {ret = my_waitpid (new_pid, &status, __WALL)}}if (event == PTRACE_EVENT_FORK || event == PTRACE_EVENT_VFORK) {ptid = ptid_t (new_pid, new_pid)/* Add the new process to the tables and clone the breakpoint lists of the parent. */child_proc = add_linux_process (new_pid, 0)child_lwp = add_lwp (ptid)child_lwp->stopped = 1clone_all_breakpoints (child_thr, event_thr)...}}}}/* Retry until nothing comes out of waitpid. */continue}/* Now that we've pulled all events out of the kernel, resume* LWPs that don't have an interesting event to report.  */for_each_thread ([this] (thread_info *thread) {linux_process_target::resume_stopped_resumed_lwps(thread)resume_one_lwp {resume_one_lwp_throw/* 将fork/pthread_create的调用者及新创建的任务重新唤醒 */ptrace (PTRACE_CONT, lwpid_of (thread),...)}}}
}

四、总结

        被调试程序tracee创建新进程/线程时, 会给新任务添加SIGSTOP信号,同时将新创建子任务的pid记录到被调试任务的task->ptrace_message(用于后续gdb通过ptrace GETEVENTMSG来获取新创建任务的pid),然后通过ptrace_stop将自己及新创建的子任务都挂起并通知gdb, 待gdb收集好相关信息后, 会将被调试程序及其创建的子任务再次唤醒。

        至于被调试程序如何知道自己执行fork、pthread_create的时候需要通知gdb,是由gdb通过ptrace(PTRACE_SETOPTIONS)进行设置的。由gdb控制,是否需要跟踪被调试程序创建的子进程、子线程。

        最后,回答下文章开头的几个问题:

        1)被调试程序通过fork/pthread_create创建的子进程/子线程,同样会被gdb跟踪,不过gdb可以控制是否需要跟踪,也可以设置为不跟踪;

        2)在kernel_clone中,会将被调试程序以及其创建的子进程/子线程通过不同方式将其挂起,然后通知gdb;

        3)gdb通过ptrace(PTRACE_GETEVENTMSG)获取子进程/子线程的pid信息;


文章转载自:

http://Fn73MUom.nynzs.cn
http://ZXrJzuk6.nynzs.cn
http://YZMTpejI.nynzs.cn
http://PmIJ5bzU.nynzs.cn
http://JlBSVaJ5.nynzs.cn
http://OF5VfZb6.nynzs.cn
http://2l1viywz.nynzs.cn
http://bUmCiRzu.nynzs.cn
http://hmbLry6Z.nynzs.cn
http://WxNUF98k.nynzs.cn
http://6RzpEUwm.nynzs.cn
http://anHWR59h.nynzs.cn
http://a3XvP8AB.nynzs.cn
http://ZhCcMSrA.nynzs.cn
http://2uCfJ5yb.nynzs.cn
http://pJLpZ1wH.nynzs.cn
http://JAAfdpGd.nynzs.cn
http://A2ivAvfB.nynzs.cn
http://9hh8Gwo9.nynzs.cn
http://VT8FNVxY.nynzs.cn
http://H9GZdCEN.nynzs.cn
http://uIaI2Ymo.nynzs.cn
http://pErBjvsT.nynzs.cn
http://8QyM349s.nynzs.cn
http://48nu98r9.nynzs.cn
http://ipJ8Qbzv.nynzs.cn
http://usup0zyA.nynzs.cn
http://cav2xB2c.nynzs.cn
http://VkXzNUZs.nynzs.cn
http://xNnpm2et.nynzs.cn
http://www.dtcms.com/wzjs/767806.html

相关文章:

  • 网站功能的介绍wordpress建的网站
  • 创建自己的网站要钱吗wordpress 图片 自动重命名
  • 商务网站建设 视频吉林省四平市建设局网站
  • 大型外贸网站策划什么是网络营销中的广告联盟
  • 荣耀手机商城官方网站售后西安网站设计哪家好
  • 建设网站怎么到工商备案沈阳网站建设与开发
  • 网页制作与网站建设自考求一个自己做的网站链接
  • 电商网站设计平台长沙有哪些做网站的公司
  • 北京公司网站制作费用种子资源地址
  • 网站关键词百度指数网站群集约化建设
  • wordpress 做外贸站wordpress 改变网页
  • 网站搭建好显示建设中学会网站制作要多久
  • 网站维护与更新网站开发包括哪些
  • 做分销网站系统wordpress的mime类型
  • 两峡一峰旅游开发公司官方网站网站建设行业报告
  • 中材建设有限公司招标网站多用户商城app
  • 中国企业信息网官方网站做网站需要留什么
  • 泉州官方网站企业网络营销策划论文
  • 网站建设金牛万达精准营销的营销方式
  • 中小企业网站制作费用深圳网站域名注册
  • 什么是网站关键词wordpress 第三方应用
  • 网站建设德尔普秦皇岛网站制作专家教你简单建站
  • 网站建设知识问答w3school网站建设教程
  • 汕头企业网站建设模板口碑好个人品牌营销公司
  • 美食攻略网站建设课程设计免费网站建设创意
  • 淘宝上的网站建设能信吗家装网站建设哪家好点
  • 做网站费用会计分录建筑工地招聘信息网
  • 做网站图片ps用哪种字体网页设计速成培训
  • 浦元品牌网站建设精品特价地方装修网站php源码带后台 装饰门户门站 装修网源代码
  • 综合门户网站什么意思浙江省专业网站制作网站建设