breakpoint.c revision 929bd57ca202fd2f2e8485ebf65d683e664f67b5
1/*
2 * This file is part of ltrace.
3 * Copyright (C) 2011 Petr Machata, Red Hat Inc.
4 * Copyright (C) 2006 Ian Wienand
5 * Copyright (C) 2002,2008,2009 Juan Cespedes
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 */
22
23#include "config.h"
24
25#include <sys/ptrace.h>
26#include <errno.h>
27#include <string.h>
28#include <stdio.h>
29
30#include "common.h"
31#include "backend.h"
32#include "sysdep.h"
33#include "breakpoint.h"
34#include "proc.h"
35#include "library.h"
36
37#ifdef ARCH_HAVE_ENABLE_BREAKPOINT
38extern void arch_enable_breakpoint(pid_t, struct breakpoint *);
39#else				/* ARCH_HAVE_ENABLE_BREAKPOINT */
40void
41arch_enable_breakpoint(pid_t pid, struct breakpoint *sbp)
42{
43	static unsigned char break_insn[] = BREAKPOINT_VALUE;
44	unsigned int i, j;
45
46	debug(DEBUG_PROCESS,
47	      "arch_enable_breakpoint: pid=%d, addr=%p, symbol=%s",
48	      pid, sbp->addr, breakpoint_name(sbp));
49
50	for (i = 0; i < 1 + ((BREAKPOINT_LENGTH - 1) / sizeof(long)); i++) {
51		long a = ptrace(PTRACE_PEEKTEXT, pid,
52				sbp->addr + i * sizeof(long), 0);
53		if (a == -1 && errno) {
54			fprintf(stderr, "enable_breakpoint"
55				" pid=%d, addr=%p, symbol=%s: %s\n",
56				pid, sbp->addr, breakpoint_name(sbp),
57				strerror(errno));
58			return;
59		}
60		for (j = 0;
61		     j < sizeof(long)
62		     && i * sizeof(long) + j < BREAKPOINT_LENGTH; j++) {
63			unsigned char *bytes = (unsigned char *)&a;
64
65			sbp->orig_value[i * sizeof(long) + j] = bytes[j];
66			bytes[j] = break_insn[i * sizeof(long) + j];
67		}
68		a = ptrace(PTRACE_POKETEXT, pid,
69			   sbp->addr + i * sizeof(long), a);
70		if (a == -1) {
71			fprintf(stderr, "enable_breakpoint"
72				" pid=%d, addr=%p, symbol=%s: %s\n",
73				pid, sbp->addr, breakpoint_name(sbp),
74				strerror(errno));
75			return;
76		}
77	}
78}
79#endif				/* ARCH_HAVE_ENABLE_BREAKPOINT */
80
81void
82enable_breakpoint(struct process *proc, struct breakpoint *sbp)
83{
84	debug(DEBUG_PROCESS, "enable_breakpoint: pid=%d, addr=%p, symbol=%s",
85	      proc->pid, sbp->addr, breakpoint_name(sbp));
86	arch_enable_breakpoint(proc->pid, sbp);
87}
88
89#ifdef ARCH_HAVE_DISABLE_BREAKPOINT
90extern void arch_disable_breakpoint(pid_t, const struct breakpoint *sbp);
91#else				/* ARCH_HAVE_DISABLE_BREAKPOINT */
92void
93arch_disable_breakpoint(pid_t pid, const struct breakpoint *sbp)
94{
95	unsigned int i, j;
96
97	debug(DEBUG_PROCESS,
98	      "arch_disable_breakpoint: pid=%d, addr=%p, symbol=%s",
99	      pid, sbp->addr, breakpoint_name(sbp));
100
101	for (i = 0; i < 1 + ((BREAKPOINT_LENGTH - 1) / sizeof(long)); i++) {
102		long a = ptrace(PTRACE_PEEKTEXT, pid,
103				sbp->addr + i * sizeof(long), 0);
104		if (a == -1 && errno) {
105			fprintf(stderr,
106				"disable_breakpoint pid=%d, addr=%p: %s\n",
107				pid, sbp->addr, strerror(errno));
108			return;
109		}
110		for (j = 0;
111		     j < sizeof(long)
112		     && i * sizeof(long) + j < BREAKPOINT_LENGTH; j++) {
113			unsigned char *bytes = (unsigned char *)&a;
114
115			bytes[j] = sbp->orig_value[i * sizeof(long) + j];
116		}
117		a = ptrace(PTRACE_POKETEXT, pid,
118			   sbp->addr + i * sizeof(long), a);
119		if (a == -1 && errno) {
120			fprintf(stderr,
121				"disable_breakpoint pid=%d, addr=%p: %s\n",
122				pid, sbp->addr, strerror(errno));
123			return;
124		}
125	}
126}
127#endif				/* ARCH_HAVE_DISABLE_BREAKPOINT */
128
129void
130disable_breakpoint(struct process *proc, struct breakpoint *sbp)
131{
132	debug(DEBUG_PROCESS, "disable_breakpoint: pid=%d, addr=%p, symbol=%s",
133	      proc->pid, sbp->addr, breakpoint_name(sbp));
134	arch_disable_breakpoint(proc->pid, sbp);
135}
136