blob: 40a84361686119095adb3d484855a3b6751e1445 [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 Machataf48031c2012-02-07 12:35:58 +010032#include "arch.h"
Petr Machatad3dc17b2012-03-21 03:23:25 +010033#include "sysdep.h"
Petr Machata9294d822012-02-07 12:35:58 +010034#include "breakpoint.h"
Petr Machata366c2f42012-02-09 19:34:36 +010035#include "proc.h"
Petr Machata2b46cfc2012-02-18 11:17:29 +010036#include "library.h"
Juan Cespedesa4850832002-03-03 02:37:50 +010037
Petr Machataf789c9c2011-07-09 10:54:27 +020038#ifdef ARCH_HAVE_ENABLE_BREAKPOINT
Petr Machatabc373262012-02-07 23:31:15 +010039extern void arch_enable_breakpoint(pid_t, struct breakpoint *);
Petr Machataf789c9c2011-07-09 10:54:27 +020040#else /* ARCH_HAVE_ENABLE_BREAKPOINT */
Juan Cespedesf1350522008-12-16 18:19:58 +010041void
Petr Machatabc373262012-02-07 23:31:15 +010042arch_enable_breakpoint(pid_t pid, struct breakpoint *sbp)
Petr Machataf789c9c2011-07-09 10:54:27 +020043{
Petr Machata28e80f62011-08-09 23:33:52 +020044 static unsigned char break_insn[] = BREAKPOINT_VALUE;
Paul Gilliam3f1219f2006-04-24 18:25:38 +020045 unsigned int i, j;
Juan Cespedesa4850832002-03-03 02:37:50 +010046
Petr Machataf0f90ed2012-04-13 18:44:12 +020047 debug(DEBUG_PROCESS,
48 "arch_enable_breakpoint: pid=%d, addr=%p, symbol=%s",
Petr Machata050b0a62012-04-03 01:30:30 +020049 pid, sbp->addr, breakpoint_name(sbp));
Juan Cespedesa4850832002-03-03 02:37:50 +010050
Ian Wienand2d45b1a2006-02-20 22:48:07 +010051 for (i = 0; i < 1 + ((BREAKPOINT_LENGTH - 1) / sizeof(long)); i++) {
Petr Machata26627682011-07-08 18:15:32 +020052 long a = ptrace(PTRACE_PEEKTEXT, pid,
53 sbp->addr + i * sizeof(long), 0);
Petr Machata81c65272012-03-21 04:57:25 +010054 if (a == -1 && errno) {
Petr Machatacc0e1e42012-04-25 13:42:07 +020055 fprintf(stderr, "enable_breakpoint"
56 " pid=%d, addr=%p, symbol=%s: %s\n",
57 pid, sbp->addr, breakpoint_name(sbp),
58 strerror(errno));
Petr Machata81c65272012-03-21 04:57:25 +010059 return;
60 }
Ian Wienand2d45b1a2006-02-20 22:48:07 +010061 for (j = 0;
62 j < sizeof(long)
63 && i * sizeof(long) + j < BREAKPOINT_LENGTH; j++) {
64 unsigned char *bytes = (unsigned char *)&a;
Juan Cespedesa4850832002-03-03 02:37:50 +010065
Paul Gilliam76c61f12006-06-14 06:55:21 +020066 sbp->orig_value[i * sizeof(long) + j] = bytes[j];
Ian Wienand2d45b1a2006-02-20 22:48:07 +010067 bytes[j] = break_insn[i * sizeof(long) + j];
Juan Cespedesa4850832002-03-03 02:37:50 +010068 }
Petr Machata949a56a2012-04-03 00:32:03 +020069 a = ptrace(PTRACE_POKETEXT, pid,
70 sbp->addr + i * sizeof(long), a);
Petr Machata81c65272012-03-21 04:57:25 +010071 if (a == -1) {
Petr Machatacc0e1e42012-04-25 13:42:07 +020072 fprintf(stderr, "enable_breakpoint"
73 " pid=%d, addr=%p, symbol=%s: %s\n",
74 pid, sbp->addr, breakpoint_name(sbp),
75 strerror(errno));
Petr Machata81c65272012-03-21 04:57:25 +010076 return;
77 }
Juan Cespedesa4850832002-03-03 02:37:50 +010078 }
79}
Ian Wienand2d45b1a2006-02-20 22:48:07 +010080#endif /* ARCH_HAVE_ENABLE_BREAKPOINT */
Juan Cespedesa4850832002-03-03 02:37:50 +010081
Petr Machataf789c9c2011-07-09 10:54:27 +020082void
Petr Machatabc373262012-02-07 23:31:15 +010083enable_breakpoint(Process *proc, struct breakpoint *sbp)
84{
Petr Machata050b0a62012-04-03 01:30:30 +020085 debug(DEBUG_PROCESS, "enable_breakpoint: pid=%d, addr=%p, symbol=%s",
86 proc->pid, sbp->addr, breakpoint_name(sbp));
Petr Machataf789c9c2011-07-09 10:54:27 +020087 arch_enable_breakpoint(proc->pid, sbp);
88}
89
Ian Wienand5570a772006-02-17 02:00:00 +010090#ifdef ARCH_HAVE_DISABLE_BREAKPOINT
Petr Machatabc373262012-02-07 23:31:15 +010091extern void arch_disable_breakpoint(pid_t, const struct breakpoint *sbp);
Petr Machataf789c9c2011-07-09 10:54:27 +020092#else /* ARCH_HAVE_DISABLE_BREAKPOINT */
Juan Cespedesf1350522008-12-16 18:19:58 +010093void
Petr Machatabc373262012-02-07 23:31:15 +010094arch_disable_breakpoint(pid_t pid, const struct breakpoint *sbp)
Petr Machataf789c9c2011-07-09 10:54:27 +020095{
Paul Gilliam3f1219f2006-04-24 18:25:38 +020096 unsigned int i, j;
Juan Cespedesa4850832002-03-03 02:37:50 +010097
Petr Machataf0f90ed2012-04-13 18:44:12 +020098 debug(DEBUG_PROCESS,
99 "arch_disable_breakpoint: pid=%d, addr=%p, symbol=%s",
Petr Machata050b0a62012-04-03 01:30:30 +0200100 pid, sbp->addr, breakpoint_name(sbp));
Juan Cespedesa4850832002-03-03 02:37:50 +0100101
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100102 for (i = 0; i < 1 + ((BREAKPOINT_LENGTH - 1) / sizeof(long)); i++) {
Petr Machata949a56a2012-04-03 00:32:03 +0200103 long a = ptrace(PTRACE_PEEKTEXT, pid,
104 sbp->addr + i * sizeof(long), 0);
105 if (a == -1 && errno) {
Petr Machatacc0e1e42012-04-25 13:42:07 +0200106 fprintf(stderr,
107 "disable_breakpoint pid=%d, addr=%p: %s\n",
108 pid, sbp->addr, strerror(errno));
Petr Machata949a56a2012-04-03 00:32:03 +0200109 return;
110 }
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100111 for (j = 0;
112 j < sizeof(long)
113 && i * sizeof(long) + j < BREAKPOINT_LENGTH; j++) {
114 unsigned char *bytes = (unsigned char *)&a;
Juan Cespedesa4850832002-03-03 02:37:50 +0100115
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100116 bytes[j] = sbp->orig_value[i * sizeof(long) + j];
Juan Cespedesa4850832002-03-03 02:37:50 +0100117 }
Petr Machata949a56a2012-04-03 00:32:03 +0200118 a = ptrace(PTRACE_POKETEXT, pid,
119 sbp->addr + i * sizeof(long), a);
120 if (a == -1 && errno) {
Petr Machatacc0e1e42012-04-25 13:42:07 +0200121 fprintf(stderr,
122 "disable_breakpoint pid=%d, addr=%p: %s\n",
123 pid, sbp->addr, strerror(errno));
Petr Machata949a56a2012-04-03 00:32:03 +0200124 return;
125 }
Juan Cespedesa4850832002-03-03 02:37:50 +0100126 }
127}
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100128#endif /* ARCH_HAVE_DISABLE_BREAKPOINT */
Petr Machataf789c9c2011-07-09 10:54:27 +0200129
130void
Petr Machatabc373262012-02-07 23:31:15 +0100131disable_breakpoint(Process *proc, struct breakpoint *sbp)
132{
Petr Machata050b0a62012-04-03 01:30:30 +0200133 debug(DEBUG_PROCESS, "disable_breakpoint: pid=%d, addr=%p, symbol=%s",
134 proc->pid, sbp->addr, breakpoint_name(sbp));
Petr Machataf789c9c2011-07-09 10:54:27 +0200135 arch_disable_breakpoint(proc->pid, sbp);
136}