2004-04-17 Randolph Chung <tausq@debian.org>
[external/binutils.git] / gdb / hppa-hpux-tdep.c
1 /* Target-dependent code for HPUX running on PA-RISC, for GDB.
2
3    Copyright 2002, 2003 Free Software Foundation, Inc.
4
5 This file is part of GDB.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
20
21 #include "defs.h"
22 #include "arch-utils.h"
23 #include "gdbcore.h"
24 #include "osabi.h"
25 #include "gdb_string.h"
26 #include "frame.h"
27 #include "symtab.h"
28 #include "objfiles.h"
29 #include "inferior.h"
30 #include "infcall.h"
31 #include "hppa-tdep.h"
32
33 #include <dl.h>
34 #include <machine/save_state.h>
35
36 /* Forward declarations.  */
37 extern void _initialize_hppa_hpux_tdep (void);
38 extern initialize_file_ftype _initialize_hppa_hpux_tdep;
39
40 typedef struct
41   {
42     struct minimal_symbol *msym;
43     CORE_ADDR solib_handle;
44     CORE_ADDR return_val;
45   }
46 args_for_find_stub;
47
48 /* FIXME: brobecker 2002-12-25.  The following functions will eventually
49    become static, after the multiarching conversion is done.  */
50 int hppa_hpux_pc_in_sigtramp (CORE_ADDR pc, char *name);
51 void hppa32_hpux_frame_saved_pc_in_sigtramp (struct frame_info *fi,
52                                              CORE_ADDR *tmp);
53 void hppa32_hpux_frame_base_before_sigtramp (struct frame_info *fi,
54                                              CORE_ADDR *tmp);
55 void hppa32_hpux_frame_find_saved_regs_in_sigtramp (struct frame_info *fi,
56                                                     CORE_ADDR *fsr);
57 void hppa64_hpux_frame_saved_pc_in_sigtramp (struct frame_info *fi,
58                                              CORE_ADDR *tmp);
59 void hppa64_hpux_frame_base_before_sigtramp (struct frame_info *fi,
60                                              CORE_ADDR *tmp);
61 void hppa64_hpux_frame_find_saved_regs_in_sigtramp (struct frame_info *fi,
62                                                     CORE_ADDR *fsr);
63
64 int
65 hppa_hpux_pc_in_sigtramp (CORE_ADDR pc, char *name)
66 {
67   /* Actually, for a PA running HPUX the kernel calls the signal handler
68      without an intermediate trampoline.  Luckily the kernel always sets
69      the return pointer for the signal handler to point to _sigreturn.  */
70   return (name && (strcmp ("_sigreturn", name) == 0));
71 }
72
73 /* For hppa32_hpux_frame_saved_pc_in_sigtramp, 
74    hppa32_hpux_frame_base_before_sigtramp and
75    hppa32_hpux_frame_find_saved_regs_in_sigtramp:
76
77    The signal context structure pointer is always saved at the base
78    of the frame which "calls" the signal handler.  We only want to find
79    the hardware save state structure, which lives 10 32bit words into
80    sigcontext structure.
81
82    Within the hardware save state structure, registers are found in the
83    same order as the register numbers in GDB.
84
85    At one time we peeked at %r31 rather than the PC queues to determine
86    what instruction took the fault.  This was done on purpose, but I don't
87    remember why.  Looking at the PC queues is really the right way, and
88    I don't remember why that didn't work when this code was originally
89    written.  */
90
91 void
92 hppa32_hpux_frame_saved_pc_in_sigtramp (struct frame_info *fi, CORE_ADDR *tmp)
93 {
94   *tmp = read_memory_integer (get_frame_base (fi) + (43 * 4), 4);
95 }
96
97 void
98 hppa32_hpux_frame_base_before_sigtramp (struct frame_info *fi,
99                                         CORE_ADDR *tmp)
100 {
101   *tmp = read_memory_integer (get_frame_base (fi) + (40 * 4), 4);
102 }
103
104 void
105 hppa32_hpux_frame_find_saved_regs_in_sigtramp (struct frame_info *fi,
106                                                CORE_ADDR *fsr)
107 {
108   int i;
109   const CORE_ADDR tmp = get_frame_base (fi) + (10 * 4);
110
111   for (i = 0; i < NUM_REGS; i++)
112     {
113       if (i == SP_REGNUM)
114         fsr[SP_REGNUM] = read_memory_integer (tmp + SP_REGNUM * 4, 4);
115       else
116         fsr[i] = tmp + i * 4;
117     }
118 }
119
120 /* For hppa64_hpux_frame_saved_pc_in_sigtramp, 
121    hppa64_hpux_frame_base_before_sigtramp and
122    hppa64_hpux_frame_find_saved_regs_in_sigtramp:
123
124    These functions are the PA64 ABI equivalents of the 32bits counterparts
125    above. See the comments there.
126
127    For PA64, the save_state structure is at an offset of 24 32-bit words
128    from the sigcontext structure. The 64 bit general registers are at an
129    offset of 640 bytes from the beginning of the save_state structure,
130    and the floating pointer register are at an offset of 256 bytes from
131    the beginning of the save_state structure.  */
132
133 void
134 hppa64_hpux_frame_saved_pc_in_sigtramp (struct frame_info *fi, CORE_ADDR *tmp)
135 {
136   *tmp = read_memory_integer
137            (get_frame_base (fi) + (24 * 4) + 640 + (33 * 8), 8);
138 }
139
140 void
141 hppa64_hpux_frame_base_before_sigtramp (struct frame_info *fi,
142                                         CORE_ADDR *tmp)
143 {
144   *tmp = read_memory_integer
145            (get_frame_base (fi) + (24 * 4) + 640 + (30 * 8), 8);
146 }
147
148 void
149 hppa64_hpux_frame_find_saved_regs_in_sigtramp (struct frame_info *fi,
150                                                CORE_ADDR *fsr)
151 {
152   int i;
153   const CORE_ADDR tmp1 = get_frame_base (fi) + (24 * 4) + 640;
154   const CORE_ADDR tmp2 = get_frame_base (fi) + (24 * 4) + 256;
155
156   for (i = 0; i < NUM_REGS; i++)
157     {
158       if (i == SP_REGNUM)
159         fsr[SP_REGNUM] = read_memory_integer (tmp1 + SP_REGNUM * 8, 8);
160       else if (i >= FP0_REGNUM)
161         fsr[i] = tmp2 + (i - FP0_REGNUM) * 8;
162       else
163         fsr[i] = tmp1 + i * 8;
164     }
165 }
166
167 /* Exception handling support for the HP-UX ANSI C++ compiler.
168    The compiler (aCC) provides a callback for exception events;
169    GDB can set a breakpoint on this callback and find out what
170    exception event has occurred. */
171
172 /* The name of the hook to be set to point to the callback function */
173 static char HP_ACC_EH_notify_hook[] = "__eh_notify_hook";
174 /* The name of the function to be used to set the hook value */
175 static char HP_ACC_EH_set_hook_value[] = "__eh_set_hook_value";
176 /* The name of the callback function in end.o */
177 static char HP_ACC_EH_notify_callback[] = "__d_eh_notify_callback";
178 /* Name of function in end.o on which a break is set (called by above) */
179 static char HP_ACC_EH_break[] = "__d_eh_break";
180 /* Name of flag (in end.o) that enables catching throws */
181 static char HP_ACC_EH_catch_throw[] = "__d_eh_catch_throw";
182 /* Name of flag (in end.o) that enables catching catching */
183 static char HP_ACC_EH_catch_catch[] = "__d_eh_catch_catch";
184 /* The enum used by aCC */
185 typedef enum
186   {
187     __EH_NOTIFY_THROW,
188     __EH_NOTIFY_CATCH
189   }
190 __eh_notification;
191
192 /* Is exception-handling support available with this executable? */
193 static int hp_cxx_exception_support = 0;
194 /* Has the initialize function been run? */
195 int hp_cxx_exception_support_initialized = 0;
196 /* Address of __eh_notify_hook */
197 static CORE_ADDR eh_notify_hook_addr = 0;
198 /* Address of __d_eh_notify_callback */
199 static CORE_ADDR eh_notify_callback_addr = 0;
200 /* Address of __d_eh_break */
201 static CORE_ADDR eh_break_addr = 0;
202 /* Address of __d_eh_catch_catch */
203 static CORE_ADDR eh_catch_catch_addr = 0;
204 /* Address of __d_eh_catch_throw */
205 static CORE_ADDR eh_catch_throw_addr = 0;
206 /* Sal for __d_eh_break */
207 static struct symtab_and_line *break_callback_sal = 0;
208
209 /* Code in end.c expects __d_pid to be set in the inferior,
210    otherwise __d_eh_notify_callback doesn't bother to call
211    __d_eh_break!  So we poke the pid into this symbol
212    ourselves.
213    0 => success
214    1 => failure  */
215 int
216 setup_d_pid_in_inferior (void)
217 {
218   CORE_ADDR anaddr;
219   struct minimal_symbol *msymbol;
220   char buf[4];                  /* FIXME 32x64? */
221
222   /* Slam the pid of the process into __d_pid; failing is only a warning!  */
223   msymbol = lookup_minimal_symbol ("__d_pid", NULL, symfile_objfile);
224   if (msymbol == NULL)
225     {
226       warning ("Unable to find __d_pid symbol in object file.");
227       warning ("Suggest linking executable with -g (links in /opt/langtools/lib/end.o).");
228       return 1;
229     }
230
231   anaddr = SYMBOL_VALUE_ADDRESS (msymbol);
232   store_unsigned_integer (buf, 4, PIDGET (inferior_ptid)); /* FIXME 32x64? */
233   if (target_write_memory (anaddr, buf, 4))     /* FIXME 32x64? */
234     {
235       warning ("Unable to write __d_pid");
236       warning ("Suggest linking executable with -g (links in /opt/langtools/lib/end.o).");
237       return 1;
238     }
239   return 0;
240 }
241
242 /* elz: Used to lookup a symbol in the shared libraries.
243    This function calls shl_findsym, indirectly through a
244    call to __d_shl_get. __d_shl_get is in end.c, which is always
245    linked in by the hp compilers/linkers. 
246    The call to shl_findsym cannot be made directly because it needs
247    to be active in target address space. 
248    inputs: - minimal symbol pointer for the function we want to look up
249    - address in target space of the descriptor for the library
250    where we want to look the symbol up.
251    This address is retrieved using the 
252    som_solib_get_solib_by_pc function (somsolib.c). 
253    output: - real address in the library of the function.          
254    note: the handle can be null, in which case shl_findsym will look for
255    the symbol in all the loaded shared libraries.
256    files to look at if you need reference on this stuff:
257    dld.c, dld_shl_findsym.c
258    end.c
259    man entry for shl_findsym */
260
261 CORE_ADDR
262 find_stub_with_shl_get (struct minimal_symbol *function, CORE_ADDR handle)
263 {
264   struct symbol *get_sym, *symbol2;
265   struct minimal_symbol *buff_minsym, *msymbol;
266   struct type *ftype;
267   struct value **args;
268   struct value *funcval;
269   struct value *val;
270
271   int x, namelen, err_value, tmp = -1;
272   CORE_ADDR endo_buff_addr, value_return_addr, errno_return_addr;
273   CORE_ADDR stub_addr;
274
275
276   args = alloca (sizeof (struct value *) * 8);          /* 6 for the arguments and one null one??? */
277   funcval = find_function_in_inferior ("__d_shl_get");
278   get_sym = lookup_symbol ("__d_shl_get", NULL, VAR_DOMAIN, NULL, NULL);
279   buff_minsym = lookup_minimal_symbol ("__buffer", NULL, NULL);
280   msymbol = lookup_minimal_symbol ("__shldp", NULL, NULL);
281   symbol2 = lookup_symbol ("__shldp", NULL, VAR_DOMAIN, NULL, NULL);
282   endo_buff_addr = SYMBOL_VALUE_ADDRESS (buff_minsym);
283   namelen = strlen (DEPRECATED_SYMBOL_NAME (function));
284   value_return_addr = endo_buff_addr + namelen;
285   ftype = check_typedef (SYMBOL_TYPE (get_sym));
286
287   /* do alignment */
288   if ((x = value_return_addr % 64) != 0)
289     value_return_addr = value_return_addr + 64 - x;
290
291   errno_return_addr = value_return_addr + 64;
292
293
294   /* set up stuff needed by __d_shl_get in buffer in end.o */
295
296   target_write_memory (endo_buff_addr, DEPRECATED_SYMBOL_NAME (function), namelen);
297
298   target_write_memory (value_return_addr, (char *) &tmp, 4);
299
300   target_write_memory (errno_return_addr, (char *) &tmp, 4);
301
302   target_write_memory (SYMBOL_VALUE_ADDRESS (msymbol),
303                        (char *) &handle, 4);
304
305   /* now prepare the arguments for the call */
306
307   args[0] = value_from_longest (TYPE_FIELD_TYPE (ftype, 0), 12);
308   args[1] = value_from_pointer (TYPE_FIELD_TYPE (ftype, 1), SYMBOL_VALUE_ADDRESS (msymbol));
309   args[2] = value_from_pointer (TYPE_FIELD_TYPE (ftype, 2), endo_buff_addr);
310   args[3] = value_from_longest (TYPE_FIELD_TYPE (ftype, 3), TYPE_PROCEDURE);
311   args[4] = value_from_pointer (TYPE_FIELD_TYPE (ftype, 4), value_return_addr);
312   args[5] = value_from_pointer (TYPE_FIELD_TYPE (ftype, 5), errno_return_addr);
313
314   /* now call the function */
315
316   val = call_function_by_hand (funcval, 6, args);
317
318   /* now get the results */
319
320   target_read_memory (errno_return_addr, (char *) &err_value, sizeof (err_value));
321
322   target_read_memory (value_return_addr, (char *) &stub_addr, sizeof (stub_addr));
323   if (stub_addr <= 0)
324     error ("call to __d_shl_get failed, error code is %d", err_value);
325
326   return (stub_addr);
327 }
328
329 /* Cover routine for find_stub_with_shl_get to pass to catch_errors */
330 static int
331 cover_find_stub_with_shl_get (void *args_untyped)
332 {
333   args_for_find_stub *args = args_untyped;
334   args->return_val = find_stub_with_shl_get (args->msym, args->solib_handle);
335   return 0;
336 }
337
338 /* Initialize exception catchpoint support by looking for the
339    necessary hooks/callbacks in end.o, etc., and set the hook value to
340    point to the required debug function
341
342    Return 0 => failure
343    1 => success          */
344
345 static int
346 initialize_hp_cxx_exception_support (void)
347 {
348   struct symtabs_and_lines sals;
349   struct cleanup *old_chain;
350   struct cleanup *canonical_strings_chain = NULL;
351   int i;
352   char *addr_start;
353   char *addr_end = NULL;
354   char **canonical = (char **) NULL;
355   int thread = -1;
356   struct symbol *sym = NULL;
357   struct minimal_symbol *msym = NULL;
358   struct objfile *objfile;
359   asection *shlib_info;
360
361   /* Detect and disallow recursion.  On HP-UX with aCC, infinite
362      recursion is a possibility because finding the hook for exception
363      callbacks involves making a call in the inferior, which means
364      re-inserting breakpoints which can re-invoke this code */
365
366   static int recurse = 0;
367   if (recurse > 0)
368     {
369       hp_cxx_exception_support_initialized = 0;
370       deprecated_exception_support_initialized = 0;
371       return 0;
372     }
373
374   hp_cxx_exception_support = 0;
375
376   /* First check if we have seen any HP compiled objects; if not,
377      it is very unlikely that HP's idiosyncratic callback mechanism
378      for exception handling debug support will be available!
379      This will percolate back up to breakpoint.c, where our callers
380      will decide to try the g++ exception-handling support instead. */
381   if (!deprecated_hp_som_som_object_present)
382     return 0;
383
384   /* We have a SOM executable with SOM debug info; find the hooks */
385
386   /* First look for the notify hook provided by aCC runtime libs */
387   /* If we find this symbol, we conclude that the executable must
388      have HP aCC exception support built in.  If this symbol is not
389      found, even though we're a HP SOM-SOM file, we may have been
390      built with some other compiler (not aCC).  This results percolates
391      back up to our callers in breakpoint.c which can decide to
392      try the g++ style of exception support instead.
393      If this symbol is found but the other symbols we require are
394      not found, there is something weird going on, and g++ support
395      should *not* be tried as an alternative.
396
397      ASSUMPTION: Only HP aCC code will have __eh_notify_hook defined.  
398      ASSUMPTION: HP aCC and g++ modules cannot be linked together. */
399
400   /* libCsup has this hook; it'll usually be non-debuggable */
401   msym = lookup_minimal_symbol (HP_ACC_EH_notify_hook, NULL, NULL);
402   if (msym)
403     {
404       eh_notify_hook_addr = SYMBOL_VALUE_ADDRESS (msym);
405       hp_cxx_exception_support = 1;
406     }
407   else
408     {
409       warning ("Unable to find exception callback hook (%s).", HP_ACC_EH_notify_hook);
410       warning ("Executable may not have been compiled debuggable with HP aCC.");
411       warning ("GDB will be unable to intercept exception events.");
412       eh_notify_hook_addr = 0;
413       hp_cxx_exception_support = 0;
414       return 0;
415     }
416
417   /* Next look for the notify callback routine in end.o */
418   /* This is always available in the SOM symbol dictionary if end.o is linked in */
419   msym = lookup_minimal_symbol (HP_ACC_EH_notify_callback, NULL, NULL);
420   if (msym)
421     {
422       eh_notify_callback_addr = SYMBOL_VALUE_ADDRESS (msym);
423       hp_cxx_exception_support = 1;
424     }
425   else
426     {
427       warning ("Unable to find exception callback routine (%s).", HP_ACC_EH_notify_callback);
428       warning ("Suggest linking executable with -g (links in /opt/langtools/lib/end.o).");
429       warning ("GDB will be unable to intercept exception events.");
430       eh_notify_callback_addr = 0;
431       return 0;
432     }
433
434 #ifndef GDB_TARGET_IS_HPPA_20W
435   /* Check whether the executable is dynamically linked or archive bound */
436   /* With an archive-bound executable we can use the raw addresses we find
437      for the callback function, etc. without modification. For an executable
438      with shared libraries, we have to do more work to find the plabel, which
439      can be the target of a call through $$dyncall from the aCC runtime support
440      library (libCsup) which is linked shared by default by aCC. */
441   /* This test below was copied from somsolib.c/somread.c.  It may not be a very
442      reliable one to test that an executable is linked shared. pai/1997-07-18 */
443   shlib_info = bfd_get_section_by_name (symfile_objfile->obfd, "$SHLIB_INFO$");
444   if (shlib_info && (bfd_section_size (symfile_objfile->obfd, shlib_info) != 0))
445     {
446       /* The minsym we have has the local code address, but that's not the
447          plabel that can be used by an inter-load-module call. */
448       /* Find solib handle for main image (which has end.o), and use that
449          and the min sym as arguments to __d_shl_get() (which does the equivalent
450          of shl_findsym()) to find the plabel. */
451
452       args_for_find_stub args;
453       static char message[] = "Error while finding exception callback hook:\n";
454
455       args.solib_handle = som_solib_get_solib_by_pc (eh_notify_callback_addr);
456       args.msym = msym;
457       args.return_val = 0;
458
459       recurse++;
460       catch_errors (cover_find_stub_with_shl_get, &args, message,
461                     RETURN_MASK_ALL);
462       eh_notify_callback_addr = args.return_val;
463       recurse--;
464
465       deprecated_exception_catchpoints_are_fragile = 1;
466
467       if (!eh_notify_callback_addr)
468         {
469           /* We can get here either if there is no plabel in the export list
470              for the main image, or if something strange happened (?) */
471           warning ("Couldn't find a plabel (indirect function label) for the exception callback.");
472           warning ("GDB will not be able to intercept exception events.");
473           return 0;
474         }
475     }
476   else
477     deprecated_exception_catchpoints_are_fragile = 0;
478 #endif
479
480   /* Now, look for the breakpointable routine in end.o */
481   /* This should also be available in the SOM symbol dict. if end.o linked in */
482   msym = lookup_minimal_symbol (HP_ACC_EH_break, NULL, NULL);
483   if (msym)
484     {
485       eh_break_addr = SYMBOL_VALUE_ADDRESS (msym);
486       hp_cxx_exception_support = 1;
487     }
488   else
489     {
490       warning ("Unable to find exception callback routine to set breakpoint (%s).", HP_ACC_EH_break);
491       warning ("Suggest linking executable with -g (link in /opt/langtools/lib/end.o).");
492       warning ("GDB will be unable to intercept exception events.");
493       eh_break_addr = 0;
494       return 0;
495     }
496
497   /* Next look for the catch enable flag provided in end.o */
498   sym = lookup_symbol (HP_ACC_EH_catch_catch, (struct block *) NULL,
499                        VAR_DOMAIN, 0, (struct symtab **) NULL);
500   if (sym)                      /* sometimes present in debug info */
501     {
502       eh_catch_catch_addr = SYMBOL_VALUE_ADDRESS (sym);
503       hp_cxx_exception_support = 1;
504     }
505   else
506     /* otherwise look in SOM symbol dict. */
507     {
508       msym = lookup_minimal_symbol (HP_ACC_EH_catch_catch, NULL, NULL);
509       if (msym)
510         {
511           eh_catch_catch_addr = SYMBOL_VALUE_ADDRESS (msym);
512           hp_cxx_exception_support = 1;
513         }
514       else
515         {
516           warning ("Unable to enable interception of exception catches.");
517           warning ("Executable may not have been compiled debuggable with HP aCC.");
518           warning ("Suggest linking executable with -g (link in /opt/langtools/lib/end.o).");
519           return 0;
520         }
521     }
522
523   /* Next look for the catch enable flag provided end.o */
524   sym = lookup_symbol (HP_ACC_EH_catch_catch, (struct block *) NULL,
525                        VAR_DOMAIN, 0, (struct symtab **) NULL);
526   if (sym)                      /* sometimes present in debug info */
527     {
528       eh_catch_throw_addr = SYMBOL_VALUE_ADDRESS (sym);
529       hp_cxx_exception_support = 1;
530     }
531   else
532     /* otherwise look in SOM symbol dict. */
533     {
534       msym = lookup_minimal_symbol (HP_ACC_EH_catch_throw, NULL, NULL);
535       if (msym)
536         {
537           eh_catch_throw_addr = SYMBOL_VALUE_ADDRESS (msym);
538           hp_cxx_exception_support = 1;
539         }
540       else
541         {
542           warning ("Unable to enable interception of exception throws.");
543           warning ("Executable may not have been compiled debuggable with HP aCC.");
544           warning ("Suggest linking executable with -g (link in /opt/langtools/lib/end.o).");
545           return 0;
546         }
547     }
548
549   /* Set the flags */
550   hp_cxx_exception_support = 2; /* everything worked so far */
551   hp_cxx_exception_support_initialized = 1;
552   deprecated_exception_support_initialized = 1;
553
554   return 1;
555 }
556
557 /* Target operation for enabling or disabling interception of
558    exception events.
559    KIND is either EX_EVENT_THROW or EX_EVENT_CATCH
560    ENABLE is either 0 (disable) or 1 (enable).
561    Return value is NULL if no support found;
562    -1 if something went wrong,
563    or a pointer to a symtab/line struct if the breakpointable
564    address was found. */
565
566 struct symtab_and_line *
567 child_enable_exception_callback (enum exception_event_kind kind, int enable)
568 {
569   char buf[4];
570
571   if (!deprecated_exception_support_initialized
572       || !hp_cxx_exception_support_initialized)
573     if (!initialize_hp_cxx_exception_support ())
574       return NULL;
575
576   switch (hp_cxx_exception_support)
577     {
578     case 0:
579       /* Assuming no HP support at all */
580       return NULL;
581     case 1:
582       /* HP support should be present, but something went wrong */
583       return (struct symtab_and_line *) -1;     /* yuck! */
584       /* there may be other cases in the future */
585     }
586
587   /* Set the EH hook to point to the callback routine */
588   store_unsigned_integer (buf, 4, enable ? eh_notify_callback_addr : 0);        /* FIXME 32x64 problem */
589   /* pai: (temp) FIXME should there be a pack operation first? */
590   if (target_write_memory (eh_notify_hook_addr, buf, 4))        /* FIXME 32x64 problem */
591     {
592       warning ("Could not write to target memory for exception event callback.");
593       warning ("Interception of exception events may not work.");
594       return (struct symtab_and_line *) -1;
595     }
596   if (enable)
597     {
598       /* Ensure that __d_pid is set up correctly -- end.c code checks this. :-( */
599       if (PIDGET (inferior_ptid) > 0)
600         {
601           if (setup_d_pid_in_inferior ())
602             return (struct symtab_and_line *) -1;
603         }
604       else
605         {
606           warning ("Internal error: Invalid inferior pid?  Cannot intercept exception events.");
607           return (struct symtab_and_line *) -1;
608         }
609     }
610
611   switch (kind)
612     {
613     case EX_EVENT_THROW:
614       store_unsigned_integer (buf, 4, enable ? 1 : 0);
615       if (target_write_memory (eh_catch_throw_addr, buf, 4))    /* FIXME 32x64? */
616         {
617           warning ("Couldn't enable exception throw interception.");
618           return (struct symtab_and_line *) -1;
619         }
620       break;
621     case EX_EVENT_CATCH:
622       store_unsigned_integer (buf, 4, enable ? 1 : 0);
623       if (target_write_memory (eh_catch_catch_addr, buf, 4))    /* FIXME 32x64? */
624         {
625           warning ("Couldn't enable exception catch interception.");
626           return (struct symtab_and_line *) -1;
627         }
628       break;
629     default:
630       error ("Request to enable unknown or unsupported exception event.");
631     }
632
633   /* Copy break address into new sal struct, malloc'ing if needed. */
634   if (!break_callback_sal)
635     {
636       break_callback_sal = (struct symtab_and_line *) xmalloc (sizeof (struct symtab_and_line));
637     }
638   init_sal (break_callback_sal);
639   break_callback_sal->symtab = NULL;
640   break_callback_sal->pc = eh_break_addr;
641   break_callback_sal->line = 0;
642   break_callback_sal->end = eh_break_addr;
643
644   return break_callback_sal;
645 }
646
647 /* Record some information about the current exception event */
648 static struct exception_event_record current_ex_event;
649 /* Convenience struct */
650 static struct symtab_and_line null_symtab_and_line =
651 {NULL, 0, 0, 0};
652
653 /* Report current exception event.  Returns a pointer to a record
654    that describes the kind of the event, where it was thrown from,
655    and where it will be caught.  More information may be reported
656    in the future */
657 struct exception_event_record *
658 child_get_current_exception_event (void)
659 {
660   CORE_ADDR event_kind;
661   CORE_ADDR throw_addr;
662   CORE_ADDR catch_addr;
663   struct frame_info *fi, *curr_frame;
664   int level = 1;
665
666   curr_frame = get_current_frame ();
667   if (!curr_frame)
668     return (struct exception_event_record *) NULL;
669
670   /* Go up one frame to __d_eh_notify_callback, because at the
671      point when this code is executed, there's garbage in the
672      arguments of __d_eh_break. */
673   fi = find_relative_frame (curr_frame, &level);
674   if (level != 0)
675     return (struct exception_event_record *) NULL;
676
677   select_frame (fi);
678
679   /* Read in the arguments */
680   /* __d_eh_notify_callback() is called with 3 arguments:
681      1. event kind catch or throw
682      2. the target address if known
683      3. a flag -- not sure what this is. pai/1997-07-17 */
684   event_kind = read_register (ARG0_REGNUM);
685   catch_addr = read_register (ARG1_REGNUM);
686
687   /* Now go down to a user frame */
688   /* For a throw, __d_eh_break is called by
689      __d_eh_notify_callback which is called by
690      __notify_throw which is called
691      from user code.
692      For a catch, __d_eh_break is called by
693      __d_eh_notify_callback which is called by
694      <stackwalking stuff> which is called by
695      __throw__<stuff> or __rethrow_<stuff> which is called
696      from user code. */
697   /* FIXME: Don't use such magic numbers; search for the frames */
698   level = (event_kind == EX_EVENT_THROW) ? 3 : 4;
699   fi = find_relative_frame (curr_frame, &level);
700   if (level != 0)
701     return (struct exception_event_record *) NULL;
702
703   select_frame (fi);
704   throw_addr = get_frame_pc (fi);
705
706   /* Go back to original (top) frame */
707   select_frame (curr_frame);
708
709   current_ex_event.kind = (enum exception_event_kind) event_kind;
710   current_ex_event.throw_sal = find_pc_line (throw_addr, 1);
711   current_ex_event.catch_sal = find_pc_line (catch_addr, 1);
712
713   return &current_ex_event;
714 }
715
716 static void
717 hppa_hpux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
718 {
719   set_gdbarch_deprecated_pc_in_sigtramp (gdbarch, hppa_hpux_pc_in_sigtramp);
720 }
721
722 static void
723 hppa_hpux_som_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
724 {
725   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
726
727   tdep->is_elf = 0;
728   hppa_hpux_init_abi (info, gdbarch);
729 }
730
731 static void
732 hppa_hpux_elf_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
733 {
734   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
735
736   tdep->is_elf = 1;
737   hppa_hpux_init_abi (info, gdbarch);
738 }
739
740 void
741 _initialize_hppa_hpux_tdep (void)
742 {
743   gdbarch_register_osabi (bfd_arch_hppa, 0, GDB_OSABI_HPUX_SOM,
744                           hppa_hpux_som_init_abi);
745   gdbarch_register_osabi (bfd_arch_hppa, bfd_mach_hppa20w, GDB_OSABI_HPUX_ELF,
746                           hppa_hpux_elf_init_abi);
747 }