ac82635d723bf52f119efc7a381300c775d58a20
[external/binutils.git] / gdb / kod-cisco.c
1 /* Kernel Object Display facility for Cisco
2    Copyright 1999 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 \f
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 *
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 (strdup ("gdbkodcisco v0.0.0 - Cisco Kernel Object Display"));
89 }
90
91 /* Close the connection.  */
92 void
93 cisco_kod_close ()
94 {
95 }
96
97 /* Print a "bad packet" message.  */
98 static void
99 bad_packet ()
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
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;
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       if (sync_len == 0)
220         sync_ids = (char **) xmalloc (count * sizeof (char *));
221       else
222         sync_ids = (char **) xrealloc (sync_ids,
223                                        (sync_len + count) * sizeof (char *));
224       sync_len += count;
225
226       for (i = 0; i < count; ++i)
227         {
228           if (strlen (&buffer[off]) < 8 || buffer[off + 8] != ';')
229             {
230               bad_packet ();
231               fail = 1;
232               break;
233             }
234           buffer[off + 8] = '\0';
235           sync_ids[sync_next++] = xstrdup (&buffer[off]);
236           off += 9;
237         }
238
239       if (buffer[off] != '\0')
240         {
241           bad_packet ();
242           fail = 1;
243           break;
244         }
245     }
246
247   /* We've collected all the sync object IDs.  Now query to get the
248      specific information, and arrange to print this info.  */
249   if (! fail)
250     {
251       (*gdb_kod_display) ("Object ID\tObject Pointer\tThread ID\n");
252
253       for (i = 0; i < sync_next; ++i)
254         {
255           int off = 0;
256           int bufsiz = PBUFSIZ;
257
258           /* For now assume a query can be accomplished in a single
259              transaction.  This is implied in the protocol document.
260              See comments above, and the KOD protocol document, to
261              understand the parsing of the return value.  */
262           strcpy (command, "aI,");
263           strcat (command, sync_ids[i]);
264           strcat (command, ";");
265
266 #ifndef FAKE_PACKET
267           (*gdb_kod_query) (command, buffer, &bufsiz);
268 #else
269           strcpy (buffer, "KAI,");
270           strcat (buffer, sync_ids[i]);
271           strcat (buffer, ",ffef00a0,cd00123d;");
272 #endif
273
274           if (strlen (buffer) == 0)
275             {
276               (*gdb_kod_display) ("Remote target did not recognize KOD command.\n");
277               break;
278             }
279
280           if (strncmp (buffer, "KAI,", 4))
281             {
282               bad_packet ();
283               break;
284             }
285           off += 4;
286
287           if (strncmp (&buffer[off], sync_ids[i], 8)
288               || buffer[off + 8] != ',')
289             {
290               bad_packet ();
291               break;
292             }
293           off += 9;
294
295           /* Extract thread id and sync object pointer.  */
296           if (strlen (&buffer[off]) != 2 * 8 + 2
297               || buffer[off + 8] != ','
298               || buffer[off + 17] != ';')
299             {
300               bad_packet ();
301               break;
302             }
303
304           buffer[off + 8] = '\0';
305           buffer[off + 17] = '\0';
306
307           /* Display the result.  */
308           (*gdb_kod_display) (sync_ids[i]);
309           (*gdb_kod_display) ("\t");
310           (*gdb_kod_display) (&buffer[off]);
311           (*gdb_kod_display) ("\t");
312           (*gdb_kod_display) (&buffer[off + 9]);
313           (*gdb_kod_display) ("\n");
314         }
315     }
316
317   /* Free memory.  */
318   for (i = 0; i < sync_next; ++i)
319     free (sync_ids[i]);
320   free (sync_ids);
321 }