blob: fe336b180b7d482af68d3a6e70dcb7cb51423c7c [file] [log] [blame]
Petr Machata64262602012-01-07 03:41:36 +01001/*
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
Juan Cespedesa4850832002-03-03 02:37:50 +010023#include "config.h"
Juan Cespedesa4850832002-03-03 02:37:50 +010024
25#include <sys/ptrace.h>
Petr Machata81c65272012-03-21 04:57:25 +010026#include <errno.h>
Petr Machataf0f90ed2012-04-13 18:44:12 +020027#include <string.h>
Petr Machatacc0e1e42012-04-25 13:42:07 +020028#include <stdio.h>
Juan Cespedes61da3372009-07-03 11:55:44 +020029
Juan Cespedes8d1b92b2009-07-03 10:39:34 +020030#include "common.h"
Petr Machata64262602012-01-07 03:41:36 +010031#include "backend.h"
Petr Machatad3dc17b2012-03-21 03:23:25 +010032#include "sysdep.h"
Petr Machata9294d822012-02-07 12:35:58 +010033#include "breakpoint.h"
Petr Machata366c2f42012-02-09 19:34:36 +010034#include "proc.h"
Petr Machata2b46cfc2012-02-18 11:17:29 +010035#include "library.h"
Juan Cespedesa4850832002-03-03 02:37:50 +010036
Petr Machataf789c9c2011-07-09 10:54:27 +020037#ifdef ARCH_HAVE_ENABLE_BREAKPOINT
Petr Machatabc373262012-02-07 23:31:15 +010038extern void arch_enable_breakpoint(pid_t, struct breakpoint *);
Petr Machataf789c9c2011-07-09 10:54:27 +020039#else /* ARCH_HAVE_ENABLE_BREAKPOINT */
Juan Cespedesf1350522008-12-16 18:19:58 +010040void
Petr Machatabc373262012-02-07 23:31:15 +010041arch_enable_breakpoint(pid_t pid, struct breakpoint *sbp)
Petr Machataf789c9c2011-07-09 10:54:27 +020042{
Petr Machata28e80f62011-08-09 23:33:52 +020043 static unsigned char break_insn[] = BREAKPOINT_VALUE;
Paul Gilliam3f1219f2006-04-24 18:25:38 +020044 unsigned int i, j;
Juan Cespedesa4850832002-03-03 02:37:50 +010045
Petr Machataf0f90ed2012-04-13 18:44:12 +020046 debug(DEBUG_PROCESS,
47 "arch_enable_breakpoint: pid=%d, addr=%p, symbol=%s",
Petr Machata050b0a62012-04-03 01:30:30 +020048 pid, sbp->addr, breakpoint_name(sbp));
Juan Cespedesa4850832002-03-03 02:37:50 +010049
Ian Wienand2d45b1a2006-02-20 22:48:07 +010050 for (i = 0; i < 1 + ((BREAKPOINT_LENGTH - 1) / sizeof(long)); i++) {
Petr Machata26627682011-07-08 18:15:32 +020051 long a = ptrace(PTRACE_PEEKTEXT, pid,
52 sbp->addr + i * sizeof(long), 0);
Petr Machata81c65272012-03-21 04:57:25 +010053 if (a == -1 && errno) {
Petr Machatacc0e1e42012-04-25 13:42:07 +020054 fprintf(stderr, "enable_breakpoint"
55 " pid=%d, addr=%p, symbol=%s: %s\n",
56 pid, sbp->addr, breakpoint_name(sbp),
57 strerror(errno));
Petr Machata81c65272012-03-21 04:57:25 +010058 return;
59 }
Ian Wienand2d45b1a2006-02-20 22:48:07 +010060 for (j = 0;
61 j < sizeof(long)
62 && i * sizeof(long) + j < BREAKPOINT_LENGTH; j++) {
63 unsigned char *bytes = (unsigned char *)&a;
Juan Cespedesa4850832002-03-03 02:37:50 +010064
Paul Gilliam76c61f12006-06-14 06:55:21 +020065 sbp->orig_value[i * sizeof(long) + j] = bytes[j];
Ian Wienand2d45b1a2006-02-20 22:48:07 +010066 bytes[j] = break_insn[i * sizeof(long) + j];
Juan Cespedesa4850832002-03-03 02:37:50 +010067 }
Petr Machata949a56a2012-04-03 00:32:03 +020068 a = ptrace(PTRACE_POKETEXT, pid,
69 sbp->addr + i * sizeof(long), a);
Petr Machata81c65272012-03-21 04:57:25 +010070 if (a == -1) {
Petr Machatacc0e1e42012-04-25 13:42:07 +020071 fprintf(stderr, "enable_breakpoint"
72 " pid=%d, addr=%p, symbol=%s: %s\n",
73 pid, sbp->addr, breakpoint_name(sbp),
74 strerror(errno));
Petr Machata81c65272012-03-21 04:57:25 +010075 return;
76 }
Juan Cespedesa4850832002-03-03 02:37:50 +010077 }
78}
Ian Wienand2d45b1a2006-02-20 22:48:07 +010079#endif /* ARCH_HAVE_ENABLE_BREAKPOINT */
Juan Cespedesa4850832002-03-03 02:37:50 +010080
Petr Machataf789c9c2011-07-09 10:54:27 +020081void
Petr Machatabc373262012-02-07 23:31:15 +010082enable_breakpoint(Process *proc, struct breakpoint *sbp)
83{
Petr Machata050b0a62012-04-03 01:30:30 +020084 debug(DEBUG_PROCESS, "enable_breakpoint: pid=%d, addr=%p, symbol=%s",
85 proc->pid, sbp->addr, breakpoint_name(sbp));
Petr Machataf789c9c2011-07-09 10:54:27 +020086 arch_enable_breakpoint(proc->pid, sbp);
87}
88
Ian Wienand5570a772006-02-17 02:00:00 +010089#ifdef ARCH_HAVE_DISABLE_BREAKPOINT
Petr Machatabc373262012-02-07 23:31:15 +010090extern void arch_disable_breakpoint(pid_t, const struct breakpoint *sbp);
Petr Machataf789c9c2011-07-09 10:54:27 +020091#else /* ARCH_HAVE_DISABLE_BREAKPOINT */
Juan Cespedesf1350522008-12-16 18:19:58 +010092void
Petr Machatabc373262012-02-07 23:31:15 +010093arch_disable_breakpoint(pid_t pid, const struct breakpoint *sbp)
Petr Machataf789c9c2011-07-09 10:54:27 +020094{
Paul Gilliam3f1219f2006-04-24 18:25:38 +020095 unsigned int i, j;
Juan Cespedesa4850832002-03-03 02:37:50 +010096
Petr Machataf0f90ed2012-04-13 18:44:12 +020097 debug(DEBUG_PROCESS,
98 "arch_disable_breakpoint: pid=%d, addr=%p, symbol=%s",
Petr Machata050b0a62012-04-03 01:30:30 +020099 pid, sbp->addr, breakpoint_name(sbp));
Juan Cespedesa4850832002-03-03 02:37:50 +0100100
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100101 for (i = 0; i < 1 + ((BREAKPOINT_LENGTH - 1) / sizeof(long)); i++) {
Petr Machata949a56a2012-04-03 00:32:03 +0200102 long a = ptrace(PTRACE_PEEKTEXT, pid,
103 sbp->addr + i * sizeof(long), 0);
104 if (a == -1 && errno) {
Petr Machatacc0e1e42012-04-25 13:42:07 +0200105 fprintf(stderr,
106 "disable_breakpoint pid=%d, addr=%p: %s\n",
107 pid, sbp->addr, strerror(errno));
Petr Machata949a56a2012-04-03 00:32:03 +0200108 return;
109 }
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100110 for (j = 0;
111 j < sizeof(long)
112 && i * sizeof(long) + j < BREAKPOINT_LENGTH; j++) {
113 unsigned char *bytes = (unsigned char *)&a;
Juan Cespedesa4850832002-03-03 02:37:50 +0100114
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100115 bytes[j] = sbp->orig_value[i * sizeof(long) + j];
Juan Cespedesa4850832002-03-03 02:37:50 +0100116 }
Petr Machata949a56a2012-04-03 00:32:03 +0200117 a = ptrace(PTRACE_POKETEXT, pid,
118 sbp->addr + i * sizeof(long), a);
119 if (a == -1 && errno) {
Petr Machatacc0e1e42012-04-25 13:42:07 +0200120 fprintf(stderr,
121 "disable_breakpoint pid=%d, addr=%p: %s\n",
122 pid, sbp->addr, strerror(errno));
Petr Machata949a56a2012-04-03 00:32:03 +0200123 return;
124 }
Juan Cespedesa4850832002-03-03 02:37:50 +0100125 }
126}
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100127#endif /* ARCH_HAVE_DISABLE_BREAKPOINT */
Petr Machataf789c9c2011-07-09 10:54:27 +0200128
129void
Petr Machatabc373262012-02-07 23:31:15 +0100130disable_breakpoint(Process *proc, struct breakpoint *sbp)
131{
Petr Machata050b0a62012-04-03 01:30:30 +0200132 debug(DEBUG_PROCESS, "disable_breakpoint: pid=%d, addr=%p, symbol=%s",
133 proc->pid, sbp->addr, breakpoint_name(sbp));
Petr Machataf789c9c2011-07-09 10:54:27 +0200134 arch_disable_breakpoint(proc->pid, sbp);
135}