154 lines
5.2 KiB
C
154 lines
5.2 KiB
C
/*
|
|
* This file is part of ltrace.
|
|
* Copyright (C) 2011,2012,2013 Petr Machata, Red Hat Inc.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation; either version 2 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
|
* 02110-1301 USA
|
|
*/
|
|
|
|
#ifndef _LTRACE_LINUX_TRACE_H_
|
|
#define _LTRACE_LINUX_TRACE_H_
|
|
|
|
#include "proc.h"
|
|
|
|
/* This publishes some Linux-specific data structures used for process
|
|
* handling. */
|
|
|
|
/**
|
|
* This is used for bookkeeping related to PIDs that the event
|
|
* handlers work with.
|
|
*/
|
|
struct pid_task {
|
|
pid_t pid; /* This may be 0 for tasks that exited
|
|
* mid-handling. */
|
|
int sigstopped : 1;
|
|
int got_event : 1;
|
|
int delivered : 1;
|
|
int vforked : 1;
|
|
int sysret : 1;
|
|
};
|
|
|
|
struct pid_set {
|
|
struct pid_task *tasks;
|
|
size_t count;
|
|
size_t alloc;
|
|
};
|
|
|
|
/**
|
|
* Breakpoint re-enablement. When we hit a breakpoint, we must
|
|
* disable it, single-step, and re-enable it. That single-step can be
|
|
* done only by one task in a task group, while others are stopped,
|
|
* otherwise the processes would race for who sees the breakpoint
|
|
* disabled and who doesn't. The following is to keep track of it
|
|
* all.
|
|
*/
|
|
struct process_stopping_handler
|
|
{
|
|
struct event_handler super;
|
|
|
|
/* The task that is doing the re-enablement. */
|
|
struct process *task_enabling_breakpoint;
|
|
|
|
/* The pointer being re-enabled. */
|
|
struct breakpoint *breakpoint_being_enabled;
|
|
|
|
/* Software singlestep breakpoints, if any needed. */
|
|
struct breakpoint *sws_bps[2];
|
|
|
|
/* When all tasks are stopped, this callback gets called. */
|
|
void (*on_all_stopped)(struct process_stopping_handler *);
|
|
|
|
/* When we get a singlestep event, this is called to decide
|
|
* whether to stop stepping, or whether to enable the
|
|
* brakpoint, sink remaining signals, and continue
|
|
* everyone. */
|
|
enum callback_status (*keep_stepping_p)
|
|
(struct process_stopping_handler *);
|
|
|
|
/* Whether we need to use ugly workaround to get around
|
|
* various problems with singlestepping. */
|
|
enum callback_status (*ugly_workaround_p)
|
|
(struct process_stopping_handler *);
|
|
|
|
enum {
|
|
/* We are waiting for everyone to land in t/T. */
|
|
PSH_STOPPING = 0,
|
|
|
|
/* We are doing the PTRACE_SINGLESTEP. */
|
|
PSH_SINGLESTEP,
|
|
|
|
/* We are waiting for all the SIGSTOPs to arrive so
|
|
* that we can sink them. */
|
|
PSH_SINKING,
|
|
|
|
/* This is for tracking the ugly workaround. */
|
|
PSH_UGLY_WORKAROUND,
|
|
} state;
|
|
|
|
int exiting;
|
|
|
|
struct pid_set pids;
|
|
};
|
|
|
|
/* Allocate a process stopping handler, initialize it and install it.
|
|
* Return 0 on success or a negative value on failure. Pass NULL for
|
|
* each callback to use a default instead. The default for
|
|
* ON_ALL_STOPPED is LINUX_PTRACE_DISABLE_AND_SINGLESTEP, the default
|
|
* for KEEP_STEPPING_P and UGLY_WORKAROUND_P is "no". */
|
|
int process_install_stopping_handler
|
|
(struct process *proc, struct breakpoint *sbp,
|
|
void (*on_all_stopped)(struct process_stopping_handler *),
|
|
enum callback_status (*keep_stepping_p)
|
|
(struct process_stopping_handler *),
|
|
enum callback_status (*ugly_workaround_p)
|
|
(struct process_stopping_handler *));
|
|
|
|
void linux_ptrace_disable_and_singlestep(struct process_stopping_handler *self);
|
|
void linux_ptrace_disable_and_continue(struct process_stopping_handler *self);
|
|
|
|
/* When main binary needs to call an IFUNC function defined in the
|
|
* binary itself, a PLT entry is set up so that dynamic linker can get
|
|
* involved and resolve the symbol. But unlike other PLT relocation,
|
|
* this one can't rely on symbol table being available. So it doesn't
|
|
* reference the symbol by its name, but by its address, and
|
|
* correspondingly, has another type. When arch backend wishes to
|
|
* support these IRELATIVE relocations, it should override
|
|
* arch_elf_add_plt_entry and dispatch to this function for IRELATIVE
|
|
* relocations.
|
|
*
|
|
* This function behaves as arch_elf_add_plt_entry, except that it
|
|
* doesn't take name for a parameter, but instead looks up the name in
|
|
* symbol tables in LTE. */
|
|
enum plt_status linux_elf_add_plt_entry_irelative(struct process *proc,
|
|
struct ltelf *lte,
|
|
GElf_Rela *rela, size_t ndx,
|
|
struct library_symbol **ret);
|
|
|
|
/* Service routine of the above. Determines a name corresponding to
|
|
* ADDR, or invents a new one. Returns NULL on failures, otherwise it
|
|
* returns a malloc'd pointer that the caller is responsible for
|
|
* freeing. */
|
|
char *linux_elf_find_irelative_name(struct ltelf *lte, GElf_Addr addr);
|
|
|
|
/* Returns ${NAME}.IFUNC in a newly-malloc'd block, or NULL on
|
|
* failures. */
|
|
char *linux_append_IFUNC_to_name(const char *name);
|
|
|
|
/* Returns a statically allocated prototype that represents the
|
|
* prototype "void *()". Never fails. */
|
|
struct prototype *linux_IFUNC_prototype(void);
|
|
|
|
|
|
#endif /* _LTRACE_LINUX_TRACE_H_ */
|