198944Sobrien/* Kernel Object Display facility for Cisco 298944Sobrien Copyright 1999, 2000 Free Software Foundation, Inc. 398944Sobrien 498944Sobrien Written by Tom Tromey <tromey@cygnus.com>. 598944Sobrien 698944SobrienThis file is part of GDB. 798944Sobrien 898944SobrienThis program is free software; you can redistribute it and/or modify 998944Sobrienit under the terms of the GNU General Public License as published by 1098944Sobrienthe Free Software Foundation; either version 2 of the License, or 1198944Sobrien(at your option) any later version. 1298944Sobrien 1398944SobrienThis program is distributed in the hope that it will be useful, 1498944Sobrienbut WITHOUT ANY WARRANTY; without even the implied warranty of 1598944SobrienMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1698944SobrienGNU General Public License for more details. 1798944Sobrien 1898944SobrienYou should have received a copy of the GNU General Public License 1998944Sobrienalong with this program; if not, write to the Free Software 2098944SobrienFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 2198944Sobrien 2298944Sobrien#include "defs.h" 2398944Sobrien#include "gdb_string.h" 2498944Sobrien#include "kod.h" 2598944Sobrien 2698944Sobrien#ifdef HAVE_STDLIB_H 2798944Sobrien#include <stdlib.h> 2898944Sobrien#endif 2998944Sobrien 3098944Sobrien/* Define this to turn off communication with target. */ 3198944Sobrien/* #define FAKE_PACKET */ 3298944Sobrien 3398944Sobrien/* Size of buffer used for remote communication. */ 3498944Sobrien#define PBUFSIZ 400 3598944Sobrien 3698944Sobrien/* Pointers to gdb callbacks. */ 3798944Sobrienstatic void (*gdb_kod_display) (char *); 3898944Sobrienstatic void (*gdb_kod_query) (char *, char *, int *); 3998944Sobrien 4098944Sobrien 4198944Sobrien 4298944Sobrien/* Initialize and return library name and version. 4398944Sobrien The gdb side of KOD, kod.c, passes us two functions: one for 4498944Sobrien displaying output (presumably to the user) and the other for 4598944Sobrien querying the target. */ 4698944Sobrienchar * 4798944Sobriencisco_kod_open (kod_display_callback_ftype *display_func, 4898944Sobrien kod_query_callback_ftype *query_func) 4998944Sobrien{ 5098944Sobrien char buffer[PBUFSIZ]; 5198944Sobrien int bufsiz = PBUFSIZ; 5298944Sobrien int i, count; 5398944Sobrien 5498944Sobrien gdb_kod_display = display_func; 5598944Sobrien gdb_kod_query = query_func; 5698944Sobrien 5798944Sobrien /* Get the OS info, and check the version field. This is the stub 5898944Sobrien version, which we use to see whether we will understand what 5998944Sobrien comes back. This is lame, but the `qKoL' request doesn't 6098944Sobrien actually provide enough configurability. 6198944Sobrien 6298944Sobrien Right now the only defined version number is `0.0.0'. 6398944Sobrien This stub supports qKoI and the `a' (any) object requests qKaL 6498944Sobrien and qKaI. Each `a' object is returned as a 4-byte integer ID. 6598944Sobrien An info request on an object returns a pair of 4-byte integers; 6698944Sobrien the first is the object pointer and the second is the thread ID. */ 6798944Sobrien 6898944Sobrien#ifndef FAKE_PACKET 6998944Sobrien (*gdb_kod_query) ("oI;", buffer, &bufsiz); 7098944Sobrien#else 7198944Sobrien strcpy (buffer, "Cisco IOS/Classic/13.4 0.0.0"); 7298944Sobrien#endif 7398944Sobrien 7498944Sobrien count = 2; 7598944Sobrien for (i = 0; count && buffer[i] != '\0'; ++i) 7698944Sobrien { 7798944Sobrien if (buffer[i] == ' ') 7898944Sobrien --count; 7998944Sobrien } 8098944Sobrien 8198944Sobrien if (buffer[i] == '\0') 8298944Sobrien error ("Remote returned malformed packet\n"); 8398944Sobrien if (strcmp (&buffer[i], "0.0.0")) 8498944Sobrien error ("Remote returned unknown stub version: %s\n", &buffer[i]); 8598944Sobrien 8698944Sobrien /* Return name, version, and description. I hope we have enough 8798944Sobrien space. */ 8898944Sobrien return (xstrdup ("gdbkodcisco v0.0.0 - Cisco Kernel Object Display")); 8998944Sobrien} 9098944Sobrien 9198944Sobrien/* Close the connection. */ 9298944Sobrienvoid 9398944Sobriencisco_kod_close (void) 9498944Sobrien{ 9598944Sobrien} 9698944Sobrien 9798944Sobrien/* Print a "bad packet" message. */ 9898944Sobrienstatic void 9998944Sobrienbad_packet (void) 10098944Sobrien{ 10198944Sobrien (*gdb_kod_display) ("Remote target returned malformed packet.\n"); 10298944Sobrien} 10398944Sobrien 10498944Sobrien/* Print information about currently known kernel objects. 10598944Sobrien We currently ignore the argument. There is only one mode of 10698944Sobrien querying the Cisco kernel: we ask for a dump of everything, and 10798944Sobrien it returns it. */ 10898944Sobrienvoid 10998944Sobriencisco_kod_request (char *arg, int from_tty) 11098944Sobrien{ 11198944Sobrien char buffer[PBUFSIZ], command[PBUFSIZ]; 11298944Sobrien int done = 0, i; 11398944Sobrien int fail = 0; 11498944Sobrien 11598944Sobrien char **sync_ids = NULL; 11698944Sobrien int sync_len = 0; 11798944Sobrien int sync_next = 0; 11898944Sobrien char *prev_id = NULL; 11998944Sobrien 12098944Sobrien if (! arg || strcmp (arg, "any")) 12198944Sobrien { 12298944Sobrien /* "Top-level" command. This is really silly, but it also seems 12398944Sobrien to be how KOD is defined. */ 12498944Sobrien /* Even sillier is the fact that this first line must start 12598944Sobrien with the word "List". See kod.tcl. */ 12698944Sobrien (*gdb_kod_display) ("List of Cisco Kernel Objects\n"); 12798944Sobrien (*gdb_kod_display) ("Object\tDescription\n"); 12898944Sobrien (*gdb_kod_display) ("any\tAny and all objects\n"); 12998944Sobrien return; 13098944Sobrien } 13198944Sobrien 13298944Sobrien while (! done) 13398944Sobrien { 13498944Sobrien int off = 0; /* Where we are in the string. */ 13598944Sobrien long count; /* Number of objects in this packet. */ 13698944Sobrien int bufsiz = PBUFSIZ; 13798944Sobrien char *s_end; 13898944Sobrien 13998944Sobrien strcpy (command, "aL"); 14098944Sobrien if (prev_id) 14198944Sobrien { 14298944Sobrien strcat (command, ","); 14398944Sobrien strcat (command, prev_id); 14498944Sobrien } 14598944Sobrien strcat (command, ";"); 14698944Sobrien 14798944Sobrien#ifndef FAKE_PACKET 14898944Sobrien /* We talk to the target by calling through the query function 14998944Sobrien passed to us when we were initialized. */ 15098944Sobrien (*gdb_kod_query) (command, buffer, &bufsiz); 15198944Sobrien#else 15298944Sobrien /* Fake up a multi-part packet. */ 15398944Sobrien if (! strncmp (&command[3], "a500005a", 8)) 15498944Sobrien strcpy (buffer, "KAL,01,1,f500005f;f500005f;"); 15598944Sobrien else 15698944Sobrien strcpy (buffer, "KAL,02,0,a500005a;a500005a;de02869f;"); 15798944Sobrien#endif 15898944Sobrien 15998944Sobrien /* Empty response is an error. */ 16098944Sobrien if (strlen (buffer) == 0) 16198944Sobrien { 16298944Sobrien (*gdb_kod_display) ("Remote target did not recognize kernel object query command.\n"); 16398944Sobrien fail = 1; 16498944Sobrien break; 16598944Sobrien } 16698944Sobrien 16798944Sobrien /* If we don't get a `K' response then the buffer holds the 16898944Sobrien target's error message. */ 16998944Sobrien if (buffer[0] != 'K') 17098944Sobrien { 17198944Sobrien (*gdb_kod_display) (buffer); 17298944Sobrien fail = 1; 17398944Sobrien break; 17498944Sobrien } 17598944Sobrien 17698944Sobrien /* Make sure we get the response we expect. */ 17798944Sobrien if (strncmp (buffer, "KAL,", 4)) 17898944Sobrien { 17998944Sobrien bad_packet (); 18098944Sobrien fail = 1; 18198944Sobrien break; 18298944Sobrien } 18398944Sobrien off += 4; 18498944Sobrien 18598944Sobrien /* Parse out the count. We expect to convert exactly two 18698944Sobrien characters followed by a comma. */ 18798944Sobrien count = strtol (&buffer[off], &s_end, 16); 18898944Sobrien if (s_end - &buffer[off] != 2 || buffer[off + 2] != ',') 18998944Sobrien { 19098944Sobrien bad_packet (); 19198944Sobrien fail = 1; 19298944Sobrien break; 19398944Sobrien } 19498944Sobrien off += 3; 19598944Sobrien 19698944Sobrien /* Parse out the `done' flag. */ 19798944Sobrien if ((buffer[off] != '0' && buffer[off] != '1') 19898944Sobrien || buffer[off + 1] != ',') 19998944Sobrien { 20098944Sobrien bad_packet (); 20198944Sobrien fail = 1; 20298944Sobrien break; 20398944Sobrien } 20498944Sobrien done = buffer[off] == '1'; 20598944Sobrien off += 2; 20698944Sobrien 20798944Sobrien /* Id of the last item; we might this to construct the next 20898944Sobrien request. */ 20998944Sobrien prev_id = &buffer[off]; 21098944Sobrien if (strlen (prev_id) < 8 || buffer[off + 8] != ';') 21198944Sobrien { 21298944Sobrien bad_packet (); 21398944Sobrien fail = 1; 21498944Sobrien break; 21598944Sobrien } 21698944Sobrien buffer[off + 8] = '\0'; 21798944Sobrien off += 9; 21898944Sobrien 21998944Sobrien sync_len += count; 22098944Sobrien sync_ids = (char **) xrealloc (sync_ids, sync_len * sizeof (char *)); 22198944Sobrien 22298944Sobrien for (i = 0; i < count; ++i) 22398944Sobrien { 22498944Sobrien if (strlen (&buffer[off]) < 8 || buffer[off + 8] != ';') 22598944Sobrien { 22698944Sobrien bad_packet (); 22798944Sobrien fail = 1; 22898944Sobrien break; 22998944Sobrien } 23098944Sobrien buffer[off + 8] = '\0'; 23198944Sobrien sync_ids[sync_next++] = xstrdup (&buffer[off]); 23298944Sobrien off += 9; 23398944Sobrien } 23498944Sobrien 23598944Sobrien if (buffer[off] != '\0') 23698944Sobrien { 23798944Sobrien bad_packet (); 23898944Sobrien fail = 1; 23998944Sobrien break; 24098944Sobrien } 24198944Sobrien } 24298944Sobrien 24398944Sobrien /* We've collected all the sync object IDs. Now query to get the 24498944Sobrien specific information, and arrange to print this info. */ 24598944Sobrien if (! fail) 24698944Sobrien { 24798944Sobrien (*gdb_kod_display) ("Object ID\tObject Pointer\tThread ID\n"); 24898944Sobrien 24998944Sobrien for (i = 0; i < sync_next; ++i) 25098944Sobrien { 25198944Sobrien int off = 0; 25298944Sobrien int bufsiz = PBUFSIZ; 25398944Sobrien 25498944Sobrien /* For now assume a query can be accomplished in a single 25598944Sobrien transaction. This is implied in the protocol document. 25698944Sobrien See comments above, and the KOD protocol document, to 25798944Sobrien understand the parsing of the return value. */ 25898944Sobrien strcpy (command, "aI,"); 25998944Sobrien strcat (command, sync_ids[i]); 26098944Sobrien strcat (command, ";"); 26198944Sobrien 26298944Sobrien#ifndef FAKE_PACKET 26398944Sobrien (*gdb_kod_query) (command, buffer, &bufsiz); 26498944Sobrien#else 26598944Sobrien strcpy (buffer, "KAI,"); 26698944Sobrien strcat (buffer, sync_ids[i]); 26798944Sobrien strcat (buffer, ",ffef00a0,cd00123d;"); 26898944Sobrien#endif 26998944Sobrien 27098944Sobrien if (strlen (buffer) == 0) 27198944Sobrien { 27298944Sobrien (*gdb_kod_display) ("Remote target did not recognize KOD command.\n"); 27398944Sobrien break; 27498944Sobrien } 27598944Sobrien 27698944Sobrien if (strncmp (buffer, "KAI,", 4)) 27798944Sobrien { 27898944Sobrien bad_packet (); 27998944Sobrien break; 28098944Sobrien } 28198944Sobrien off += 4; 28298944Sobrien 28398944Sobrien if (strncmp (&buffer[off], sync_ids[i], 8) 28498944Sobrien || buffer[off + 8] != ',') 28598944Sobrien { 28698944Sobrien bad_packet (); 28798944Sobrien break; 28898944Sobrien } 28998944Sobrien off += 9; 29098944Sobrien 29198944Sobrien /* Extract thread id and sync object pointer. */ 29298944Sobrien if (strlen (&buffer[off]) != 2 * 8 + 2 29398944Sobrien || buffer[off + 8] != ',' 29498944Sobrien || buffer[off + 17] != ';') 29598944Sobrien { 29698944Sobrien bad_packet (); 29798944Sobrien break; 29898944Sobrien } 29998944Sobrien 30098944Sobrien buffer[off + 8] = '\0'; 30198944Sobrien buffer[off + 17] = '\0'; 30298944Sobrien 30398944Sobrien /* Display the result. */ 30498944Sobrien (*gdb_kod_display) (sync_ids[i]); 30598944Sobrien (*gdb_kod_display) ("\t"); 30698944Sobrien (*gdb_kod_display) (&buffer[off]); 30798944Sobrien (*gdb_kod_display) ("\t"); 30898944Sobrien (*gdb_kod_display) (&buffer[off + 9]); 30998944Sobrien (*gdb_kod_display) ("\n"); 31098944Sobrien } 31198944Sobrien } 31298944Sobrien 31398944Sobrien /* Free memory. */ 31498944Sobrien for (i = 0; i < sync_next; ++i) 31598944Sobrien xfree (sync_ids[i]); 31698944Sobrien xfree (sync_ids); 31798944Sobrien} 318