1 /* Kernel Object Display facility for Cisco
2    Copyright 1999, 2000 Free Software Foundation, Inc.
3 
4    Written by Tom Tromey <tromey@cygnus.com>.
5 
6 This file is part of GDB.
7 
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12 
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
21 
22 #include "defs.h"
23 #include "gdb_string.h"
24 #include "kod.h"
25 
26 #ifdef HAVE_STDLIB_H
27 #include <stdlib.h>
28 #endif
29 
30 /* Define this to turn off communication with target.  */
31 /* #define FAKE_PACKET */
32 
33 /* Size of buffer used for remote communication.  */
34 #define PBUFSIZ 400
35 
36 /* Pointers to gdb callbacks.  */
37 static void (*gdb_kod_display) (char *);
38 static void (*gdb_kod_query) (char *, char *, int *);
39 
40 
41 
42 /* Initialize and return library name and version.
43    The gdb side of KOD, kod.c, passes us two functions: one for
44    displaying output (presumably to the user) and the other for
45    querying the target.  */
46 char *
cisco_kod_open(kod_display_callback_ftype * display_func,kod_query_callback_ftype * query_func)47 cisco_kod_open (kod_display_callback_ftype *display_func,
48 		kod_query_callback_ftype *query_func)
49 {
50   char buffer[PBUFSIZ];
51   int bufsiz = PBUFSIZ;
52   int i, count;
53 
54   gdb_kod_display = display_func;
55   gdb_kod_query = query_func;
56 
57   /* Get the OS info, and check the version field.  This is the stub
58      version, which we use to see whether we will understand what
59      comes back.  This is lame, but the `qKoL' request doesn't
60      actually provide enough configurability.
61 
62      Right now the only defined version number is `0.0.0'.
63      This stub supports qKoI and the `a' (any) object requests qKaL
64      and qKaI.  Each `a' object is returned as a 4-byte integer ID.
65      An info request on an object returns a pair of 4-byte integers;
66      the first is the object pointer and the second is the thread ID.  */
67 
68 #ifndef FAKE_PACKET
69   (*gdb_kod_query) ("oI;", buffer, &bufsiz);
70 #else
71   strcpy (buffer, "Cisco IOS/Classic/13.4 0.0.0");
72 #endif
73 
74   count = 2;
75   for (i = 0; count && buffer[i] != '\0'; ++i)
76     {
77       if (buffer[i] == ' ')
78 	--count;
79     }
80 
81   if (buffer[i] == '\0')
82     error ("Remote returned malformed packet\n");
83   if (strcmp (&buffer[i], "0.0.0"))
84     error ("Remote returned unknown stub version: %s\n", &buffer[i]);
85 
86   /* Return name, version, and description.  I hope we have enough
87      space.  */
88   return (xstrdup ("gdbkodcisco v0.0.0 - Cisco Kernel Object Display"));
89 }
90 
91 /* Close the connection.  */
92 void
cisco_kod_close(void)93 cisco_kod_close (void)
94 {
95 }
96 
97 /* Print a "bad packet" message.  */
98 static void
bad_packet(void)99 bad_packet (void)
100 {
101   (*gdb_kod_display) ("Remote target returned malformed packet.\n");
102 }
103 
104 /* Print information about currently known kernel objects.
105    We currently ignore the argument.  There is only one mode of
106    querying the Cisco kernel: we ask for a dump of everything, and
107    it returns it.  */
108 void
cisco_kod_request(char * arg,int from_tty)109 cisco_kod_request (char *arg, int from_tty)
110 {
111   char buffer[PBUFSIZ], command[PBUFSIZ];
112   int done = 0, i;
113   int fail = 0;
114 
115   char **sync_ids = NULL;
116   int sync_len = 0;
117   int sync_next = 0;
118   char *prev_id = NULL;
119 
120   if (! arg || strcmp (arg, "any"))
121     {
122       /* "Top-level" command.  This is really silly, but it also seems
123 	 to be how KOD is defined.  */
124       /* Even sillier is the fact that this first line must start
125 	 with the word "List".  See kod.tcl.  */
126       (*gdb_kod_display) ("List of Cisco Kernel Objects\n");
127       (*gdb_kod_display) ("Object\tDescription\n");
128       (*gdb_kod_display) ("any\tAny and all objects\n");
129       return;
130     }
131 
132   while (! done)
133     {
134       int off = 0;		/* Where we are in the string.  */
135       long count;		/* Number of objects in this packet.  */
136       int bufsiz = PBUFSIZ;
137       char *s_end;
138 
139       strcpy (command, "aL");
140       if (prev_id)
141 	{
142 	  strcat (command, ",");
143 	  strcat (command, prev_id);
144 	}
145       strcat (command, ";");
146 
147 #ifndef FAKE_PACKET
148       /* We talk to the target by calling through the query function
149 	 passed to us when we were initialized.  */
150       (*gdb_kod_query) (command, buffer, &bufsiz);
151 #else
152       /* Fake up a multi-part packet.  */
153       if (! strncmp (&command[3], "a500005a", 8))
154 	strcpy (buffer, "KAL,01,1,f500005f;f500005f;");
155       else
156 	strcpy (buffer, "KAL,02,0,a500005a;a500005a;de02869f;");
157 #endif
158 
159       /* Empty response is an error.  */
160       if (strlen (buffer) == 0)
161 	{
162 	  (*gdb_kod_display) ("Remote target did not recognize kernel object query command.\n");
163 	  fail = 1;
164 	  break;
165 	}
166 
167       /* If we don't get a `K' response then the buffer holds the
168 	 target's error message.  */
169       if (buffer[0] != 'K')
170 	{
171 	  (*gdb_kod_display) (buffer);
172 	  fail = 1;
173 	  break;
174 	}
175 
176       /* Make sure we get the response we expect.  */
177       if (strncmp (buffer, "KAL,", 4))
178 	{
179 	  bad_packet ();
180 	  fail = 1;
181 	  break;
182 	}
183       off += 4;
184 
185       /* Parse out the count.  We expect to convert exactly two
186 	 characters followed by a comma.  */
187       count = strtol (&buffer[off], &s_end, 16);
188       if (s_end - &buffer[off] != 2 || buffer[off + 2] != ',')
189 	{
190 	  bad_packet ();
191 	  fail = 1;
192 	  break;
193 	}
194       off += 3;
195 
196       /* Parse out the `done' flag.  */
197       if ((buffer[off] != '0' && buffer[off] != '1')
198 	  || buffer[off + 1] != ',')
199 	{
200 	  bad_packet ();
201 	  fail = 1;
202 	  break;
203 	}
204       done = buffer[off] == '1';
205       off += 2;
206 
207       /* Id of the last item; we might this to construct the next
208 	 request.  */
209       prev_id = &buffer[off];
210       if (strlen (prev_id) < 8 || buffer[off + 8] != ';')
211 	{
212 	  bad_packet ();
213 	  fail = 1;
214 	  break;
215 	}
216       buffer[off + 8] = '\0';
217       off += 9;
218 
219       sync_len += count;
220       sync_ids = (char **) xrealloc (sync_ids, sync_len * sizeof (char *));
221 
222       for (i = 0; i < count; ++i)
223 	{
224 	  if (strlen (&buffer[off]) < 8 || buffer[off + 8] != ';')
225 	    {
226 	      bad_packet ();
227 	      fail = 1;
228 	      break;
229 	    }
230 	  buffer[off + 8] = '\0';
231 	  sync_ids[sync_next++] = xstrdup (&buffer[off]);
232 	  off += 9;
233 	}
234 
235       if (buffer[off] != '\0')
236 	{
237 	  bad_packet ();
238 	  fail = 1;
239 	  break;
240 	}
241     }
242 
243   /* We've collected all the sync object IDs.  Now query to get the
244      specific information, and arrange to print this info.  */
245   if (! fail)
246     {
247       (*gdb_kod_display) ("Object ID\tObject Pointer\tThread ID\n");
248 
249       for (i = 0; i < sync_next; ++i)
250 	{
251 	  int off = 0;
252 	  int bufsiz = PBUFSIZ;
253 
254 	  /* For now assume a query can be accomplished in a single
255 	     transaction.  This is implied in the protocol document.
256 	     See comments above, and the KOD protocol document, to
257 	     understand the parsing of the return value.  */
258 	  strcpy (command, "aI,");
259 	  strcat (command, sync_ids[i]);
260 	  strcat (command, ";");
261 
262 #ifndef FAKE_PACKET
263 	  (*gdb_kod_query) (command, buffer, &bufsiz);
264 #else
265 	  strcpy (buffer, "KAI,");
266 	  strcat (buffer, sync_ids[i]);
267 	  strcat (buffer, ",ffef00a0,cd00123d;");
268 #endif
269 
270 	  if (strlen (buffer) == 0)
271 	    {
272 	      (*gdb_kod_display) ("Remote target did not recognize KOD command.\n");
273 	      break;
274 	    }
275 
276 	  if (strncmp (buffer, "KAI,", 4))
277 	    {
278 	      bad_packet ();
279 	      break;
280 	    }
281 	  off += 4;
282 
283 	  if (strncmp (&buffer[off], sync_ids[i], 8)
284 	      || buffer[off + 8] != ',')
285 	    {
286 	      bad_packet ();
287 	      break;
288 	    }
289 	  off += 9;
290 
291 	  /* Extract thread id and sync object pointer.  */
292 	  if (strlen (&buffer[off]) != 2 * 8 + 2
293 	      || buffer[off + 8] != ','
294 	      || buffer[off + 17] != ';')
295 	    {
296 	      bad_packet ();
297 	      break;
298 	    }
299 
300 	  buffer[off + 8] = '\0';
301 	  buffer[off + 17] = '\0';
302 
303 	  /* Display the result.  */
304 	  (*gdb_kod_display) (sync_ids[i]);
305 	  (*gdb_kod_display) ("\t");
306 	  (*gdb_kod_display) (&buffer[off]);
307 	  (*gdb_kod_display) ("\t");
308 	  (*gdb_kod_display) (&buffer[off + 9]);
309 	  (*gdb_kod_display) ("\n");
310 	}
311     }
312 
313   /* Free memory.  */
314   for (i = 0; i < sync_next; ++i)
315     xfree (sync_ids[i]);
316   xfree (sync_ids);
317 }
318