diff options
Diffstat (limited to 'gdb/kod-cisco.c')
-rw-r--r-- | gdb/kod-cisco.c | 321 |
1 files changed, 321 insertions, 0 deletions
diff --git a/gdb/kod-cisco.c b/gdb/kod-cisco.c new file mode 100644 index 0000000..b33b9e5 --- /dev/null +++ b/gdb/kod-cisco.c @@ -0,0 +1,321 @@ +/* Kernel Object Display facility for Cisco + Copyright 1999 Free Software Foundation, Inc. + + Written by Tom Tromey <tromey@cygnus.com>. + +This file is part of GDB. + +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. */ + +#include "defs.h" +#include "gdb_string.h" + +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif + +/* Define this to turn off communication with target. */ +/* #define FAKE_PACKET */ + +/* Size of buffer used for remote communication. */ +#define PBUFSIZ 400 + +/* Pointers to gdb callbacks. */ +static void (*gdb_kod_display) (char *); +static void (*gdb_kod_query) (char *, char *, int *); + + + +/* Initialize and return library name and version. + The gdb side of KOD, kod.c, passes us two functions: one for + displaying output (presumably to the user) and the other for + querying the target. */ +char * +cisco_kod_open (char *arg, + void (*display_func) (char *), + void (*query_func) (char *, char *, int *)) +{ + char buffer[PBUFSIZ]; + int bufsiz = PBUFSIZ; + int i, count; + + gdb_kod_display = display_func; + gdb_kod_query = query_func; + + /* Get the OS info, and check the version field. This is the stub + version, which we use to see whether we will understand what + comes back. This is lame, but the `qKoL' request doesn't + actually provide enough configurability. + + Right now the only defined version number is `0.0.0'. + This stub supports qKoI and the `a' (any) object requests qKaL + and qKaI. Each `a' object is returned as a 4-byte integer ID. + An info request on an object returns a pair of 4-byte integers; + the first is the object pointer and the second is the thread ID. */ + +#ifndef FAKE_PACKET + (*gdb_kod_query) ("oI;", buffer, &bufsiz); +#else + strcpy (buffer, "Cisco IOS/Classic/13.4 0.0.0"); +#endif + + count = 2; + for (i = 0; count && buffer[i] != '\0'; ++i) + { + if (buffer[i] == ' ') + --count; + } + + if (buffer[i] == '\0') + error ("Remote returned malformed packet\n"); + if (strcmp (&buffer[i], "0.0.0")) + error ("Remote returned unknown stub version: %s\n", &buffer[i]); + + /* Return name, version, and description. I hope we have enough + space. */ + return (strdup ("gdbkodcisco v0.0.0 - Cisco Kernel Object Display")); +} + +/* Close the connection. */ +void +cisco_kod_close () +{ +} + +/* Print a "bad packet" message. */ +static void +bad_packet () +{ + (*gdb_kod_display) ("Remote target returned malformed packet.\n"); +} + +/* Print information about currently known kernel objects. + We currently ignore the argument. There is only one mode of + querying the Cisco kernel: we ask for a dump of everything, and + it returns it. */ +void +cisco_kod_request (char *arg, int from_tty) +{ + char buffer[PBUFSIZ], command[PBUFSIZ]; + int done = 0, i; + int fail = 0; + + char **sync_ids; + int sync_len = 0; + int sync_next = 0; + char *prev_id = NULL; + + if (! arg || strcmp (arg, "any")) + { + /* "Top-level" command. This is really silly, but it also seems + to be how KOD is defined. */ + /* Even sillier is the fact that this first line must start + with the word "List". See kod.tcl. */ + (*gdb_kod_display) ("List of Cisco Kernel Objects\n"); + (*gdb_kod_display) ("Object\tDescription\n"); + (*gdb_kod_display) ("any\tAny and all objects\n"); + return; + } + + while (! done) + { + int off = 0; /* Where we are in the string. */ + long count; /* Number of objects in this packet. */ + int bufsiz = PBUFSIZ; + char *s_end; + + strcpy (command, "aL"); + if (prev_id) + { + strcat (command, ","); + strcat (command, prev_id); + } + strcat (command, ";"); + +#ifndef FAKE_PACKET + /* We talk to the target by calling through the query function + passed to us when we were initialized. */ + (*gdb_kod_query) (command, buffer, &bufsiz); +#else + /* Fake up a multi-part packet. */ + if (! strncmp (&command[3], "a500005a", 8)) + strcpy (buffer, "KAL,01,1,f500005f;f500005f;"); + else + strcpy (buffer, "KAL,02,0,a500005a;a500005a;de02869f;"); +#endif + + /* Empty response is an error. */ + if (strlen (buffer) == 0) + { + (*gdb_kod_display) ("Remote target did not recognize kernel object query command.\n"); + fail = 1; + break; + } + + /* If we don't get a `K' response then the buffer holds the + target's error message. */ + if (buffer[0] != 'K') + { + (*gdb_kod_display) (buffer); + fail = 1; + break; + } + + /* Make sure we get the response we expect. */ + if (strncmp (buffer, "KAL,", 4)) + { + bad_packet (); + fail = 1; + break; + } + off += 4; + + /* Parse out the count. We expect to convert exactly two + characters followed by a comma. */ + count = strtol (&buffer[off], &s_end, 16); + if (s_end - &buffer[off] != 2 || buffer[off + 2] != ',') + { + bad_packet (); + fail = 1; + break; + } + off += 3; + + /* Parse out the `done' flag. */ + if ((buffer[off] != '0' && buffer[off] != '1') + || buffer[off + 1] != ',') + { + bad_packet (); + fail = 1; + break; + } + done = buffer[off] == '1'; + off += 2; + + /* Id of the last item; we might this to construct the next + request. */ + prev_id = &buffer[off]; + if (strlen (prev_id) < 8 || buffer[off + 8] != ';') + { + bad_packet (); + fail = 1; + break; + } + buffer[off + 8] = '\0'; + off += 9; + + if (sync_len == 0) + sync_ids = (char **) xmalloc (count * sizeof (char *)); + else + sync_ids = (char **) xrealloc (sync_ids, + (sync_len + count) * sizeof (char *)); + sync_len += count; + + for (i = 0; i < count; ++i) + { + if (strlen (&buffer[off]) < 8 || buffer[off + 8] != ';') + { + bad_packet (); + fail = 1; + break; + } + buffer[off + 8] = '\0'; + sync_ids[sync_next++] = xstrdup (&buffer[off]); + off += 9; + } + + if (buffer[off] != '\0') + { + bad_packet (); + fail = 1; + break; + } + } + + /* We've collected all the sync object IDs. Now query to get the + specific information, and arrange to print this info. */ + if (! fail) + { + (*gdb_kod_display) ("Object ID\tObject Pointer\tThread ID\n"); + + for (i = 0; i < sync_next; ++i) + { + int off = 0; + int bufsiz = PBUFSIZ; + + /* For now assume a query can be accomplished in a single + transaction. This is implied in the protocol document. + See comments above, and the KOD protocol document, to + understand the parsing of the return value. */ + strcpy (command, "aI,"); + strcat (command, sync_ids[i]); + strcat (command, ";"); + +#ifndef FAKE_PACKET + (*gdb_kod_query) (command, buffer, &bufsiz); +#else + strcpy (buffer, "KAI,"); + strcat (buffer, sync_ids[i]); + strcat (buffer, ",ffef00a0,cd00123d;"); +#endif + + if (strlen (buffer) == 0) + { + (*gdb_kod_display) ("Remote target did not recognize KOD command.\n"); + break; + } + + if (strncmp (buffer, "KAI,", 4)) + { + bad_packet (); + break; + } + off += 4; + + if (strncmp (&buffer[off], sync_ids[i], 8) + || buffer[off + 8] != ',') + { + bad_packet (); + break; + } + off += 9; + + /* Extract thread id and sync object pointer. */ + if (strlen (&buffer[off]) != 2 * 8 + 2 + || buffer[off + 8] != ',' + || buffer[off + 17] != ';') + { + bad_packet (); + break; + } + + buffer[off + 8] = '\0'; + buffer[off + 17] = '\0'; + + /* Display the result. */ + (*gdb_kod_display) (sync_ids[i]); + (*gdb_kod_display) ("\t"); + (*gdb_kod_display) (&buffer[off]); + (*gdb_kod_display) ("\t"); + (*gdb_kod_display) (&buffer[off + 9]); + (*gdb_kod_display) ("\n"); + } + } + + /* Free memory. */ + for (i = 0; i < sync_next; ++i) + free (sync_ids[i]); + free (sync_ids); +} |