1 /* BFD back-end for CISCO crash dumps.
2    Copyright (C) 1994-2021 Free Software Foundation, Inc.
3 
4    This file is part of BFD, the Binary File Descriptor library.
5 
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19    MA 02110-1301, USA.  */
20 
21 #include "sysdep.h"
22 #include "bfd.h"
23 #include "libbfd.h"
24 /* core_file_failing_signal returns a host signal (this probably should
25    be fixed).  */
26 #include <signal.h>
27 
28 /* for MSVC builds */
29 #ifndef SIGTRAP
30 # define SIGTRAP 5
31 #endif
32 #ifndef SIGEMT
33 # define SIGEMT 6
34 #endif
35 #ifndef SIGBUS
36 # define SIGBUS 10
37 #endif
38 
39 int crash_info_locs[] =
40 {
41   0x0250,	/* mips, ppc, x86, i960 */
42   0x0400,	/* m68k, mips, x86, i960 */
43   0x0FFC,	/* m68k, mips, ppc, x86, i960 */
44   0x3000,	/* ppc */
45   0x4FFC,	/* m68k */
46   -1
47 };
48 
49 #define CRASH_MAGIC	0xdead1234
50 #define MASK_ADDR(x)	((x) & 0x0fffffff)	/* Mask crash info address */
51 
52 typedef enum
53 {
54   CRASH_REASON_NOTCRASHED = 0,
55   CRASH_REASON_EXCEPTION = 1,
56   CRASH_REASON_CORRUPT = 2,
57 } crashreason;
58 
59 typedef struct
60 {
61   char magic[4];		/* Magic number */
62   char version[4];		/* Version number */
63   char reason[4];		/* Crash reason */
64   char cpu_vector[4];		/* CPU vector for exceptions */
65   char registers[4];		/* Pointer to saved registers */
66   char rambase[4];		/* Base of RAM (not in V1 crash info) */
67   char textbase[4];		/* Base of .text section (not in V3 crash info) */
68   char database[4];		/* Base of .data section (not in V3 crash info) */
69   char bssbase[4];		/* Base of .bss section (not in V3 crash info) */
70 } crashinfo_external;
71 
72 struct cisco_core_struct
73 {
74   int sig;
75 };
76 
77 #define cisco_core_file_matches_executable_p generic_core_file_matches_executable_p
78 #define cisco_core_file_pid _bfd_nocore_core_file_pid
79 
80 /* Examine the file for a crash info struct at the offset given by
81    CRASH_INFO_LOC.  */
82 
83 static bfd_cleanup
cisco_core_file_validate(bfd * abfd,int crash_info_loc)84 cisco_core_file_validate (bfd *abfd, int crash_info_loc)
85 {
86   char buf[4];
87   unsigned int crashinfo_offset;
88   crashinfo_external crashinfo;
89   bfd_size_type nread;
90   unsigned int magic;
91   unsigned int version;
92   unsigned int rambase;
93   sec_ptr asect;
94   struct stat statbuf;
95   size_t amt;
96   flagword flags;
97 
98   if (bfd_seek (abfd, (file_ptr) crash_info_loc, SEEK_SET) != 0)
99     return NULL;
100 
101   nread = bfd_bread (buf, (bfd_size_type) 4, abfd);
102   if (nread != 4)
103     {
104       if (bfd_get_error () != bfd_error_system_call)
105 	bfd_set_error (bfd_error_wrong_format);
106       return NULL;
107     }
108   crashinfo_offset = MASK_ADDR (bfd_get_32 (abfd, buf));
109 
110   if (bfd_seek (abfd, (file_ptr) crashinfo_offset, SEEK_SET) != 0)
111     {
112       /* Most likely we failed because of a bogus (huge) offset */
113       bfd_set_error (bfd_error_wrong_format);
114       return NULL;
115     }
116 
117   nread = bfd_bread (&crashinfo, (bfd_size_type) sizeof (crashinfo), abfd);
118   if (nread != sizeof (crashinfo))
119     {
120       if (bfd_get_error () != bfd_error_system_call)
121 	bfd_set_error (bfd_error_wrong_format);
122       return NULL;
123     }
124 
125   if (bfd_stat (abfd, &statbuf) < 0)
126     {
127       bfd_set_error (bfd_error_system_call);
128       return NULL;
129     }
130 
131   magic = bfd_get_32 (abfd, crashinfo.magic);
132   if (magic != CRASH_MAGIC)
133     {
134       bfd_set_error (bfd_error_wrong_format);
135       return NULL;
136     }
137 
138   version = bfd_get_32 (abfd, crashinfo.version);
139   if (version == 0)
140     {
141       bfd_set_error (bfd_error_wrong_format);
142       return NULL;
143     }
144   else if (version == 1)
145     {
146       /* V1 core dumps don't specify the dump base, assume 0 */
147       rambase = 0;
148     }
149   else
150     {
151       rambase = bfd_get_32 (abfd, crashinfo.rambase);
152     }
153 
154   /* OK, we believe you.  You're a core file.  */
155 
156   amt = sizeof (struct cisco_core_struct);
157   abfd->tdata.cisco_core_data = (struct cisco_core_struct *) bfd_zmalloc (amt);
158   if (abfd->tdata.cisco_core_data == NULL)
159     return NULL;
160 
161   switch ((crashreason) bfd_get_32 (abfd, crashinfo.reason))
162     {
163     case CRASH_REASON_NOTCRASHED:
164       /* Crash file probably came from write core.  */
165       abfd->tdata.cisco_core_data->sig = 0;
166       break;
167     case CRASH_REASON_CORRUPT:
168       /* The crash context area was corrupt -- proceed with caution.
169 	 We have no way of passing this information back to the caller.  */
170       abfd->tdata.cisco_core_data->sig = 0;
171       break;
172     case CRASH_REASON_EXCEPTION:
173       /* Crash occured due to CPU exception.  */
174 
175       /* This is 68k-specific; for MIPS we'll need to interpret
176 	 cpu_vector differently based on the target configuration
177 	 (since CISCO core files don't seem to have the processor
178 	 encoded in them).  */
179 
180       switch (bfd_get_32 (abfd, crashinfo.cpu_vector))
181 	{
182 	   /* bus error		  */
183 	case 2 : abfd->tdata.cisco_core_data->sig = SIGBUS; break;
184 	   /* address error	  */
185 	case 3 : abfd->tdata.cisco_core_data->sig = SIGBUS; break;
186 	   /* illegal instruction */
187 	case 4 : abfd->tdata.cisco_core_data->sig = SIGILL;  break;
188 	   /* zero divide	  */
189 	case 5 : abfd->tdata.cisco_core_data->sig = SIGFPE;  break;
190 	   /* chk instruction	  */
191 	case 6 : abfd->tdata.cisco_core_data->sig = SIGFPE; break;
192 	   /* trapv instruction	  */
193 	case 7 : abfd->tdata.cisco_core_data->sig = SIGFPE; break;
194 	   /* privilege violation */
195 	case 8 : abfd->tdata.cisco_core_data->sig = SIGSEGV; break;
196 	   /* trace trap	  */
197 	case 9 : abfd->tdata.cisco_core_data->sig = SIGTRAP;  break;
198 	   /* line 1010 emulator  */
199 	case 10: abfd->tdata.cisco_core_data->sig = SIGILL;  break;
200 	   /* line 1111 emulator  */
201 	case 11: abfd->tdata.cisco_core_data->sig = SIGILL;  break;
202 
203 	  /* Coprocessor protocol violation.  Using a standard MMU or FPU
204 	     this cannot be triggered by software.  Call it a SIGBUS.  */
205 	case 13: abfd->tdata.cisco_core_data->sig = SIGBUS;  break;
206 
207 	  /* interrupt		 */
208 	case 31: abfd->tdata.cisco_core_data->sig = SIGINT;  break;
209 	  /* breakpoint		 */
210 	case 33: abfd->tdata.cisco_core_data->sig = SIGTRAP;  break;
211 
212 	  /* floating point err	 */
213 	case 48: abfd->tdata.cisco_core_data->sig = SIGFPE;  break;
214 	  /* floating point err	 */
215 	case 49: abfd->tdata.cisco_core_data->sig = SIGFPE;  break;
216 	  /* zero divide	 */
217 	case 50: abfd->tdata.cisco_core_data->sig = SIGFPE;  break;
218 	  /* underflow		 */
219 	case 51: abfd->tdata.cisco_core_data->sig = SIGFPE;  break;
220 	  /* operand error	 */
221 	case 52: abfd->tdata.cisco_core_data->sig = SIGFPE;  break;
222 	   /* overflow		  */
223 	case 53: abfd->tdata.cisco_core_data->sig = SIGFPE;  break;
224 	  /* NAN		 */
225 	case 54: abfd->tdata.cisco_core_data->sig = SIGFPE;  break;
226 	default:
227 #ifndef SIGEMT
228 #define SIGEMT SIGTRAP
229 #endif
230 	  /* "software generated"*/
231 	  abfd->tdata.cisco_core_data->sig = SIGEMT;
232 	}
233       break;
234     default:
235       /* Unknown crash reason.  */
236       abfd->tdata.cisco_core_data->sig = 0;
237       break;
238     }
239 
240   /* Create a ".data" section that maps the entire file, which is
241      essentially a dump of the target system's RAM.  */
242 
243   flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS;
244   asect = bfd_make_section_anyway_with_flags (abfd, ".data", flags);
245   if (asect == NULL)
246     goto error_return;
247   /* The size of memory is the size of the core file itself.  */
248   asect->size = statbuf.st_size;
249   asect->vma = rambase;
250   asect->filepos = 0;
251 
252   /* Create a ".crash" section to allow access to the saved
253      crash information.  */
254 
255   flags = SEC_HAS_CONTENTS;
256   asect = bfd_make_section_anyway_with_flags (abfd, ".crash", flags);
257   if (asect == NULL)
258     goto error_return;
259   asect->vma = 0;
260   asect->filepos = crashinfo_offset;
261   asect->size = sizeof (crashinfo);
262 
263   /* Create a ".reg" section to allow access to the saved
264      registers.  */
265 
266   asect = bfd_make_section_anyway_with_flags (abfd, ".reg", flags);
267   if (asect == NULL)
268     goto error_return;
269   asect->vma = 0;
270   asect->filepos = bfd_get_32 (abfd, crashinfo.registers) - rambase;
271   /* Since we don't know the exact size of the saved register info,
272      choose a register section size that is either the remaining part
273      of the file, or 1024, whichever is smaller.  */
274   nread = statbuf.st_size - asect->filepos;
275   asect->size = (nread < 1024) ? nread : 1024;
276 
277   return _bfd_no_cleanup;
278 
279   /* Get here if we have already started filling out the BFD
280      and there is an error of some kind.  */
281 
282  error_return:
283   bfd_release (abfd, abfd->tdata.any);
284   abfd->tdata.any = NULL;
285   bfd_section_list_clear (abfd);
286   return NULL;
287 }
288 
289 static bfd_cleanup
cisco_core_file_p(bfd * abfd)290 cisco_core_file_p (bfd *abfd)
291 {
292   int *crash_info_locp;
293   bfd_cleanup cleanup = NULL;
294 
295   for (crash_info_locp = crash_info_locs;
296        *crash_info_locp != -1 && cleanup == NULL;
297        crash_info_locp++)
298     {
299       cleanup = cisco_core_file_validate (abfd, *crash_info_locp);
300     }
301   return cleanup;
302 }
303 
304 static char *
cisco_core_file_failing_command(bfd * abfd ATTRIBUTE_UNUSED)305 cisco_core_file_failing_command (bfd *abfd ATTRIBUTE_UNUSED)
306 {
307   return NULL;
308 }
309 
310 static int
cisco_core_file_failing_signal(bfd * abfd ATTRIBUTE_UNUSED)311 cisco_core_file_failing_signal (bfd *abfd ATTRIBUTE_UNUSED)
312 {
313   return abfd->tdata.cisco_core_data->sig;
314 }
315 
316 extern const bfd_target core_cisco_le_vec;
317 
318 const bfd_target core_cisco_be_vec =
319 {
320   "cisco-ios-core-big",
321   bfd_target_unknown_flavour,
322   BFD_ENDIAN_BIG,		/* target byte order */
323   BFD_ENDIAN_BIG,		/* target headers byte order */
324   (HAS_RELOC | EXEC_P		/* object flags */
325    | HAS_LINENO | HAS_DEBUG
326    | HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
327   (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
328   0,				/* symbol prefix */
329   ' ',				/* ar_pad_char */
330   16,				/* ar_max_namelen */
331   0,				/* match priority.  */
332   TARGET_KEEP_UNUSED_SECTION_SYMBOLS, /* keep unused section symbols.  */
333   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
334   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
335   bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */
336   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
337   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
338   bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */
339 
340   {				/* bfd_check_format */
341     _bfd_dummy_target,			/* unknown format */
342     _bfd_dummy_target,			/* object file */
343     _bfd_dummy_target,			/* archive */
344     cisco_core_file_p			/* a core file */
345   },
346   {				/* bfd_set_format */
347     _bfd_bool_bfd_false_error,
348     _bfd_bool_bfd_false_error,
349     _bfd_bool_bfd_false_error,
350     _bfd_bool_bfd_false_error
351   },
352   {				/* bfd_write_contents */
353     _bfd_bool_bfd_false_error,
354     _bfd_bool_bfd_false_error,
355     _bfd_bool_bfd_false_error,
356     _bfd_bool_bfd_false_error
357   },
358 
359   BFD_JUMP_TABLE_GENERIC (_bfd_generic),
360   BFD_JUMP_TABLE_COPY (_bfd_generic),
361   BFD_JUMP_TABLE_CORE (cisco),
362   BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
363   BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols),
364   BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
365   BFD_JUMP_TABLE_WRITE (_bfd_generic),
366   BFD_JUMP_TABLE_LINK (_bfd_nolink),
367   BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
368 
369   &core_cisco_le_vec,
370 
371   NULL				/* backend_data */
372 };
373 
374 const bfd_target core_cisco_le_vec =
375 {
376   "cisco-ios-core-little",
377   bfd_target_unknown_flavour,
378   BFD_ENDIAN_LITTLE,		/* target byte order */
379   BFD_ENDIAN_LITTLE,		/* target headers byte order */
380   (HAS_RELOC | EXEC_P		/* object flags */
381    | HAS_LINENO | HAS_DEBUG
382    | HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
383   (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
384   0,				/* symbol prefix */
385   ' ',				/* ar_pad_char */
386   16,				/* ar_max_namelen */
387   0,				/* match_priority */
388   TARGET_KEEP_UNUSED_SECTION_SYMBOLS, /* keep unused section symbols.  */
389   bfd_getl64, bfd_getl_signed_64, bfd_putl64,
390   bfd_getl32, bfd_getl_signed_32, bfd_putl32,
391   bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */
392   bfd_getl64, bfd_getl_signed_64, bfd_putl64,
393   bfd_getl32, bfd_getl_signed_32, bfd_putl32,
394   bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */
395 
396   {				/* bfd_check_format */
397     _bfd_dummy_target,			/* unknown format */
398     _bfd_dummy_target,			/* object file */
399     _bfd_dummy_target,			/* archive */
400     cisco_core_file_p			/* a core file */
401   },
402   {				/* bfd_set_format */
403     _bfd_bool_bfd_false_error,
404     _bfd_bool_bfd_false_error,
405     _bfd_bool_bfd_false_error,
406     _bfd_bool_bfd_false_error
407   },
408   {				/* bfd_write_contents */
409     _bfd_bool_bfd_false_error,
410     _bfd_bool_bfd_false_error,
411     _bfd_bool_bfd_false_error,
412     _bfd_bool_bfd_false_error
413   },
414 
415   BFD_JUMP_TABLE_GENERIC (_bfd_generic),
416   BFD_JUMP_TABLE_COPY (_bfd_generic),
417   BFD_JUMP_TABLE_CORE (cisco),
418   BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
419   BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols),
420   BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
421   BFD_JUMP_TABLE_WRITE (_bfd_generic),
422   BFD_JUMP_TABLE_LINK (_bfd_nolink),
423   BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
424 
425   &core_cisco_be_vec,
426 
427   NULL				/* backend_data */
428 };
429