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