2 * This file is based on a patch submitted by Mark Wielaard <mjw@redhat.com>
4 * https://anonscm.debian.org/cgit/collab-maint/ltrace.git/commit/?id=dfefa9f057857735a073ea655f5cb34351032c8e
6 * It was re-licensed for strace by the original author:
7 * https://lists.strace.io/pipermail/strace-devel/2018-March/008063.html
9 * Copyright (c) 2014-2018 Mark Wielaard <mjw@redhat.com>
10 * Copyright (c) 2018 Masatake YAMATO <yamato@redhat.com>
11 * Copyright (c) 2018 The strace developers.
12 * All rights reserved.
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
17 * 1. Redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the distribution.
22 * 3. The name of the author may not be used to endorse or promote products
23 * derived from this software without specific prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
26 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
29 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 #include "mmap_notify.h"
40 #include <elfutils/libdwfl.h>
44 unsigned int last_proc_updating;
47 static unsigned int mapping_generation;
50 update_mapping_generation(struct tcb *tcp, void *unused)
58 mmap_notify_register_client(update_mapping_generation, NULL);
62 tcb_init(struct tcb *tcp)
64 static const Dwfl_Callbacks proc_callbacks = {
65 .find_elf = dwfl_linux_proc_find_elf,
66 .find_debuginfo = dwfl_standard_find_debuginfo
69 Dwfl *dwfl = dwfl_begin(&proc_callbacks);
71 error_msg("dwfl_begin: %s", dwfl_errmsg(-1));
75 int r = dwfl_linux_proc_attach(dwfl, tcp->pid, true);
77 const char *msg = NULL;
80 msg = dwfl_errmsg(-1);
84 error_msg("dwfl_linux_proc_attach returned an error"
85 " for process %d: %s", tcp->pid, msg);
90 struct ctx *ctx = xmalloc(sizeof(*ctx));
92 ctx->last_proc_updating = 0;
97 tcb_fin(struct tcb *tcp)
99 struct ctx *ctx = tcp->unwind_ctx;
107 flush_cache_maybe(struct tcb *tcp)
109 struct ctx *ctx = tcp->unwind_ctx;
113 if (ctx->last_proc_updating == mapping_generation)
116 int r = dwfl_linux_proc_report(ctx->dwfl, tcp->pid);
119 error_msg("dwfl_linux_proc_report returned an error"
120 " for pid %d: %s", tcp->pid, dwfl_errmsg(-1));
122 error_msg("dwfl_linux_proc_report returned an error"
123 " for pid %d", tcp->pid);
124 else if (dwfl_report_end(ctx->dwfl, NULL, NULL) != 0)
125 error_msg("dwfl_report_end returned an error"
126 " for pid %d: %s", tcp->pid, dwfl_errmsg(-1));
128 ctx->last_proc_updating = mapping_generation;
131 struct frame_user_data {
132 unwind_call_action_fn call_action;
133 unwind_error_action_fn error_action;
139 frame_callback(Dwfl_Frame *state, void *arg)
141 struct frame_user_data *user_data = arg;
145 if (!dwfl_frame_pc(state, &pc, &isactivation)) {
146 /* Propagate the error to the caller. */
153 Dwfl *dwfl = dwfl_thread_dwfl(dwfl_frame_thread(state));
154 Dwfl_Module *mod = dwfl_addrmodule(dwfl, pc);
158 const char *modname = NULL;
159 const char *symname = NULL;
161 Dwarf_Addr true_offset = pc;
163 modname = dwfl_module_info(mod, NULL, NULL, NULL, NULL,
165 symname = dwfl_module_addrinfo(mod, pc, &off, &sym,
167 dwfl_module_relocate_address(mod, &true_offset);
168 user_data->call_action(user_data->data, modname, symname,
171 /* Max number of frames to print reached? */
172 if (user_data->stack_depth-- == 0)
173 return DWARF_CB_ABORT;
179 tcb_walk(struct tcb *tcp,
180 unwind_call_action_fn call_action,
181 unwind_error_action_fn error_action,
184 struct ctx *ctx = tcp->unwind_ctx;
188 struct frame_user_data user_data = {
189 .call_action = call_action,
190 .error_action = error_action,
195 flush_cache_maybe(tcp);
197 int r = dwfl_getthread_frames(ctx->dwfl, tcp->pid, frame_callback,
201 r < 0 ? dwfl_errmsg(-1) : "too many stack frames",
205 const struct unwind_unwinder_t unwinder = {
208 .tcb_init = tcb_init,
210 .tcb_walk = tcb_walk,