summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJim Blandy <jimb@redhat.com>2004-11-01 04:37:09 +0000
committerJim Blandy <jimb@redhat.com>2004-11-01 04:37:09 +0000
commit29b5eae80db50ce0992c8a563a9b0e2e647e991d (patch)
tree85a86e1e28f46486ef31f60ab7b128fc8abb6318
parentafd807f0786d044a01a1f421ffebc0aa6018ae0e (diff)
downloadgdb-29b5eae80db50ce0992c8a563a9b0e2e647e991d.tar.gz
* stock-breakpoints.c: #include all headers necessary to get
prototypes for functions used in this file. * thread-db.c: Same.
-rw-r--r--rda/unix/ChangeLog4
-rw-r--r--rda/unix/stock-breakpoints.c258
-rw-r--r--rda/unix/thread-db.c1
3 files changed, 263 insertions, 0 deletions
diff --git a/rda/unix/ChangeLog b/rda/unix/ChangeLog
index 8e542f100ae..00e37ef09ac 100644
--- a/rda/unix/ChangeLog
+++ b/rda/unix/ChangeLog
@@ -1,5 +1,9 @@
2004-10-31 Jim Blandy <jimb@redhat.com>
+ * stock-breakpoints.c: #include all headers necessary to get
+ prototypes for functions used in this file.
+ * thread-db.c: Same.
+
* server.c (main): Initialize infd, outfd, and speed.
(tty_raw): Use proper name for speed_t "zero baud" value.
diff --git a/rda/unix/stock-breakpoints.c b/rda/unix/stock-breakpoints.c
new file mode 100644
index 00000000000..513aac85f42
--- /dev/null
+++ b/rda/unix/stock-breakpoints.c
@@ -0,0 +1,258 @@
+/* stock-breakpoints.c
+
+ Copyright 2004 Red Hat, Inc.
+
+ This file is part of RDA, the Red Hat Debug Agent (and library).
+
+ 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., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Alternative licenses for RDA may be arranged by contacting Red Hat,
+ Inc. */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "gdbserv.h"
+#include "gdbserv-target.h"
+#include "gdbserv-utils.h"
+#include "server.h"
+#include "stock-breakpoints.h"
+
+struct stock_bp
+{
+ /* All breakpoints in a table are kept in a doubly-linked ring, with
+ the table's HEAD member as the head of the ring. */
+ struct stock_bp *prev, *next;
+
+ /* The table to which this breakpoint belongs. */
+ struct stock_bp_table *table;
+
+ /* The address at which this breakpoint is set. */
+ struct gdbserv_reg addr;
+
+ /* The reference count for this breakpoint. (You must delete this
+ breakpoint this many times before it actually goes away.) */
+ int ref_count;
+
+ /* The original contents of the memory at the breakpoint address,
+ before we wrote the breakpoint instructions into it. The length
+ is taken from TABLE. */
+ void *saved;
+};
+
+struct stock_bp_table
+{
+ /* The head of a doubly-linked ring of breakpoints. */
+ struct stock_bp head;
+
+ /* The gdbserver whose breakpoints we manage, and a target to use to
+ talk to it. */
+ struct gdbserv *serv;
+ struct gdbserv_target *target;
+
+ /* The target we use to operate on PROCESS. */
+
+ /* The breakpoint instruction we store, and its length. */
+ size_t bp_insn_len;
+ void *bp_insn_data;
+};
+
+
+struct stock_bp_table *
+stock_bp_make_table (struct gdbserv *serv,
+ struct gdbserv_target *target)
+{
+ struct stock_bp_table *t = malloc (sizeof (*t));
+
+ memset (t, 0, sizeof (*t));
+ t->head.prev = t->head.next = &t->head;
+ t->serv = serv;
+ t->target = target;
+ t->bp_insn_len = 0;
+}
+
+
+struct gdbserv *
+stock_bp_table_serv (struct stock_bp_table *table)
+{
+ return table->serv;
+}
+
+
+struct gdbserv_target *
+stock_bp_table_target (struct stock_bp_table *table)
+{
+ return table->target;
+}
+
+
+void
+stock_bp_set_bp_insn (struct stock_bp_table *t,
+ size_t len, void *data)
+{
+ t->bp_insn_len = len;
+ t->bp_insn_data = malloc (len);
+ memcpy (t->bp_insn_data, data, len);
+}
+
+
+struct stock_bp *
+stock_bp_set_bp (struct stock_bp_table *table,
+ struct gdbserv_reg *addr)
+{
+ struct gdbserv *serv = table->serv;
+ struct gdbserv_target *target = table->target;
+ struct stock_bp *b;
+ unsigned long long addr_int;
+ int status;
+
+ gdbserv_reg_to_ulonglong (serv, addr, &addr_int);
+
+ /* Search the breakpoint table for a breakpoint at this address. */
+ for (b = table->head.next; b != &table->head; b = b->next)
+ {
+ unsigned long long bp_addr_int;
+
+ gdbserv_reg_to_ulonglong (serv, &b->addr, &bp_addr_int);
+ if (addr_int == bp_addr_int)
+ {
+ /* We've found an extant breakpoint at the same address.
+ Increment its reference count, and return it. */
+ b->ref_count++;
+ return b;
+ }
+
+ /* If this breakpoint partially overlaps the one we're
+ inserting, that seems like either a mistake, or something
+ that arch-specific code would need to deal with (in which
+ case this breakpoint implementation is not appropriate for
+ that architecture), so print a warning.
+
+ Keep in mind the oddities of unsigned arithmetic and
+ comparison; think carefully before simplifying this. */
+ if (bp_addr_int - addr_int < table->bp_insn_len
+ || addr_int - bp_addr_int < table->bp_insn_len)
+ fprintf (stderr, "warning: new breakpoint at 0x%llx overlaps "
+ "existing breakpoint at 0x%llx\n",
+ addr_int, bp_addr_int);
+ }
+
+ /* We didn't find any existing breakpoint, so let's make a new one. */
+ b = malloc (sizeof (*b));
+
+ memset (b, 0, sizeof (*b));
+ b->next = table->head.next;
+ b->prev = &table->head;
+ b->table = table;
+ memcpy (&b->addr, addr, sizeof (b->addr));
+ b->ref_count = 1;
+ b->saved = malloc (table->bp_insn_len);
+
+ /* Save the old contents of the memory at addr. */
+ status = target->get_mem (serv, addr, b->saved, table->bp_insn_len);
+ if (status != table->bp_insn_len)
+ {
+ fprintf (stderr,
+ "warning: couldn't save memory under breakpoint at 0x%llx\n",
+ addr_int);
+ free (b->saved);
+ free (b);
+ return 0;
+ }
+
+ /* Write the breakpoint instruction. */
+ status = target->set_mem (serv, addr,
+ table->bp_insn_data, table->bp_insn_len);
+ if (status != table->bp_insn_len)
+ {
+ fprintf (stderr,
+ "warning: couldn't write breakpoint to memory at 0x%llx\n",
+ addr_int);
+ free (b->saved);
+ free (b);
+ return 0;
+ }
+
+ /* Flush the instruction caches. */
+ target->flush_i_cache (serv);
+
+ /* Link the successfully-inserted breakpoint into the table. */
+ table->head.next->prev = b;
+ table->head.next = b;
+
+ return b;
+}
+
+
+int
+stock_bp_delete_bp (struct stock_bp *b)
+{
+ struct stock_bp_table *table = b->table;
+ struct gdbserv *serv = table->serv;
+ struct gdbserv_target *target = table->target;
+ int status;
+
+ /* Drop a reference to this breakpoint. */
+ if (--b->ref_count > 0)
+ /* There are still other references to this breakpoint, so leave
+ it in. */
+ return 0;
+
+ /* Unlink this breakpoint from its table. */
+ b->next->prev = b->prev;
+ b->prev->next = b->next;
+
+ /* Write the original breakpoint contents back to memory. */
+ status = target->set_mem (serv, &b->addr, b->saved, table->bp_insn_len);
+ if (status != table->bp_insn_len)
+ {
+ unsigned long long bp_addr_int;
+
+ gdbserv_reg_to_ulonglong (serv, &b->addr, &bp_addr_int);
+ fprintf (stderr,
+ "warning: couldn't remove breakpoint at 0x%llx\n",
+ bp_addr_int);
+
+ free (b->saved);
+ free (b);
+ return -1;
+ }
+
+ /* Flush the instruction caches. */
+ target->flush_i_cache (serv);
+
+ free (b->saved);
+ free (b);
+ return 0;
+}
+
+
+struct stock_bp_table *
+stock_bp_table (struct stock_bp *breakpoint)
+{
+ return breakpoint->table;
+}
+
+
+void
+stock_bp_addr (struct gdbserv_reg *addr,
+ struct stock_bp *breakpoint)
+{
+ memcpy (addr, &breakpoint->addr, sizeof (*addr));
+}
diff --git a/rda/unix/thread-db.c b/rda/unix/thread-db.c
index 084f1b6c0c5..ccad280afe5 100644
--- a/rda/unix/thread-db.c
+++ b/rda/unix/thread-db.c
@@ -26,6 +26,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <dlfcn.h>
#include <thread_db.h>
#include <signal.h>