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