1b725ae77Skettenis /* Target-dependent code for HPUX running on PA-RISC, for GDB.
2b725ae77Skettenis 
3b725ae77Skettenis    Copyright 2002, 2003 Free Software Foundation, Inc.
4b725ae77Skettenis 
5b725ae77Skettenis This file is part of GDB.
6b725ae77Skettenis 
7b725ae77Skettenis This program is free software; you can redistribute it and/or modify
8b725ae77Skettenis it under the terms of the GNU General Public License as published by
9b725ae77Skettenis the Free Software Foundation; either version 2 of the License, or
10b725ae77Skettenis (at your option) any later version.
11b725ae77Skettenis 
12b725ae77Skettenis This program is distributed in the hope that it will be useful,
13b725ae77Skettenis but WITHOUT ANY WARRANTY; without even the implied warranty of
14b725ae77Skettenis MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15b725ae77Skettenis GNU General Public License for more details.
16b725ae77Skettenis 
17b725ae77Skettenis You should have received a copy of the GNU General Public License
18b725ae77Skettenis along with this program; if not, write to the Free Software
19b725ae77Skettenis Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
20b725ae77Skettenis 
21b725ae77Skettenis #include "defs.h"
22b725ae77Skettenis #include "arch-utils.h"
23b725ae77Skettenis #include "gdbcore.h"
24b725ae77Skettenis #include "osabi.h"
25b725ae77Skettenis #include "gdb_string.h"
26b725ae77Skettenis #include "frame.h"
27*11efff7fSkettenis #include "frame-unwind.h"
28*11efff7fSkettenis #include "trad-frame.h"
29*11efff7fSkettenis #include "symtab.h"
30*11efff7fSkettenis #include "objfiles.h"
31*11efff7fSkettenis #include "inferior.h"
32*11efff7fSkettenis #include "infcall.h"
33*11efff7fSkettenis #include "observer.h"
34*11efff7fSkettenis #include "hppa-tdep.h"
35*11efff7fSkettenis 
36*11efff7fSkettenis #include <dl.h>
37*11efff7fSkettenis #include <machine/save_state.h>
38*11efff7fSkettenis 
39*11efff7fSkettenis #ifndef offsetof
40*11efff7fSkettenis #define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER)
41*11efff7fSkettenis #endif
42b725ae77Skettenis 
43b725ae77Skettenis /* Forward declarations.  */
44b725ae77Skettenis extern void _initialize_hppa_hpux_tdep (void);
45b725ae77Skettenis extern initialize_file_ftype _initialize_hppa_hpux_tdep;
46b725ae77Skettenis 
47*11efff7fSkettenis typedef struct
48*11efff7fSkettenis   {
49*11efff7fSkettenis     struct minimal_symbol *msym;
50*11efff7fSkettenis     CORE_ADDR solib_handle;
51*11efff7fSkettenis     CORE_ADDR return_val;
52*11efff7fSkettenis   }
53*11efff7fSkettenis args_for_find_stub;
54b725ae77Skettenis 
55*11efff7fSkettenis /* Return one if PC is in the call path of a trampoline, else return zero.
56*11efff7fSkettenis 
57*11efff7fSkettenis    Note we return one for *any* call trampoline (long-call, arg-reloc), not
58*11efff7fSkettenis    just shared library trampolines (import, export).  */
59*11efff7fSkettenis 
60*11efff7fSkettenis static int
hppa32_hpux_in_solib_call_trampoline(CORE_ADDR pc,char * name)61*11efff7fSkettenis hppa32_hpux_in_solib_call_trampoline (CORE_ADDR pc, char *name)
62*11efff7fSkettenis {
63*11efff7fSkettenis   struct minimal_symbol *minsym;
64*11efff7fSkettenis   struct unwind_table_entry *u;
65*11efff7fSkettenis 
66*11efff7fSkettenis   /* First see if PC is in one of the two C-library trampolines.  */
67*11efff7fSkettenis   if (pc == hppa_symbol_address("$$dyncall")
68*11efff7fSkettenis       || pc == hppa_symbol_address("_sr4export"))
69*11efff7fSkettenis     return 1;
70*11efff7fSkettenis 
71*11efff7fSkettenis   minsym = lookup_minimal_symbol_by_pc (pc);
72*11efff7fSkettenis   if (minsym && strcmp (DEPRECATED_SYMBOL_NAME (minsym), ".stub") == 0)
73*11efff7fSkettenis     return 1;
74*11efff7fSkettenis 
75*11efff7fSkettenis   /* Get the unwind descriptor corresponding to PC, return zero
76*11efff7fSkettenis      if no unwind was found.  */
77*11efff7fSkettenis   u = find_unwind_entry (pc);
78*11efff7fSkettenis   if (!u)
79*11efff7fSkettenis     return 0;
80*11efff7fSkettenis 
81*11efff7fSkettenis   /* If this isn't a linker stub, then return now.  */
82*11efff7fSkettenis   if (u->stub_unwind.stub_type == 0)
83*11efff7fSkettenis     return 0;
84*11efff7fSkettenis 
85*11efff7fSkettenis   /* By definition a long-branch stub is a call stub.  */
86*11efff7fSkettenis   if (u->stub_unwind.stub_type == LONG_BRANCH)
87*11efff7fSkettenis     return 1;
88*11efff7fSkettenis 
89*11efff7fSkettenis   /* The call and return path execute the same instructions within
90*11efff7fSkettenis      an IMPORT stub!  So an IMPORT stub is both a call and return
91*11efff7fSkettenis      trampoline.  */
92*11efff7fSkettenis   if (u->stub_unwind.stub_type == IMPORT)
93*11efff7fSkettenis     return 1;
94*11efff7fSkettenis 
95*11efff7fSkettenis   /* Parameter relocation stubs always have a call path and may have a
96*11efff7fSkettenis      return path.  */
97*11efff7fSkettenis   if (u->stub_unwind.stub_type == PARAMETER_RELOCATION
98*11efff7fSkettenis       || u->stub_unwind.stub_type == EXPORT)
99*11efff7fSkettenis     {
100*11efff7fSkettenis       CORE_ADDR addr;
101*11efff7fSkettenis 
102*11efff7fSkettenis       /* Search forward from the current PC until we hit a branch
103*11efff7fSkettenis          or the end of the stub.  */
104*11efff7fSkettenis       for (addr = pc; addr <= u->region_end; addr += 4)
105*11efff7fSkettenis 	{
106*11efff7fSkettenis 	  unsigned long insn;
107*11efff7fSkettenis 
108*11efff7fSkettenis 	  insn = read_memory_integer (addr, 4);
109*11efff7fSkettenis 
110*11efff7fSkettenis 	  /* Does it look like a bl?  If so then it's the call path, if
111*11efff7fSkettenis 	     we find a bv or be first, then we're on the return path.  */
112*11efff7fSkettenis 	  if ((insn & 0xfc00e000) == 0xe8000000)
113*11efff7fSkettenis 	    return 1;
114*11efff7fSkettenis 	  else if ((insn & 0xfc00e001) == 0xe800c000
115*11efff7fSkettenis 		   || (insn & 0xfc000000) == 0xe0000000)
116*11efff7fSkettenis 	    return 0;
117*11efff7fSkettenis 	}
118*11efff7fSkettenis 
119*11efff7fSkettenis       /* Should never happen.  */
120*11efff7fSkettenis       warning ("Unable to find branch in parameter relocation stub.\n");
121*11efff7fSkettenis       return 0;
122*11efff7fSkettenis     }
123*11efff7fSkettenis 
124*11efff7fSkettenis   /* Unknown stub type.  For now, just return zero.  */
125*11efff7fSkettenis   return 0;
126*11efff7fSkettenis }
127*11efff7fSkettenis 
128*11efff7fSkettenis static int
hppa64_hpux_in_solib_call_trampoline(CORE_ADDR pc,char * name)129*11efff7fSkettenis hppa64_hpux_in_solib_call_trampoline (CORE_ADDR pc, char *name)
130*11efff7fSkettenis {
131*11efff7fSkettenis   /* PA64 has a completely different stub/trampoline scheme.  Is it
132*11efff7fSkettenis      better?  Maybe.  It's certainly harder to determine with any
133*11efff7fSkettenis      certainty that we are in a stub because we can not refer to the
134*11efff7fSkettenis      unwinders to help.
135*11efff7fSkettenis 
136*11efff7fSkettenis      The heuristic is simple.  Try to lookup the current PC value in th
137*11efff7fSkettenis      minimal symbol table.  If that fails, then assume we are not in a
138*11efff7fSkettenis      stub and return.
139*11efff7fSkettenis 
140*11efff7fSkettenis      Then see if the PC value falls within the section bounds for the
141*11efff7fSkettenis      section containing the minimal symbol we found in the first
142*11efff7fSkettenis      step.  If it does, then assume we are not in a stub and return.
143*11efff7fSkettenis 
144*11efff7fSkettenis      Finally peek at the instructions to see if they look like a stub.  */
145*11efff7fSkettenis   struct minimal_symbol *minsym;
146*11efff7fSkettenis   asection *sec;
147*11efff7fSkettenis   CORE_ADDR addr;
148*11efff7fSkettenis   int insn, i;
149*11efff7fSkettenis 
150*11efff7fSkettenis   minsym = lookup_minimal_symbol_by_pc (pc);
151*11efff7fSkettenis   if (! minsym)
152*11efff7fSkettenis     return 0;
153*11efff7fSkettenis 
154*11efff7fSkettenis   sec = SYMBOL_BFD_SECTION (minsym);
155*11efff7fSkettenis 
156*11efff7fSkettenis   if (bfd_get_section_vma (sec->owner, sec) <= pc
157*11efff7fSkettenis       && pc < (bfd_get_section_vma (sec->owner, sec)
158*11efff7fSkettenis 		 + bfd_section_size (sec->owner, sec)))
159*11efff7fSkettenis       return 0;
160*11efff7fSkettenis 
161*11efff7fSkettenis   /* We might be in a stub.  Peek at the instructions.  Stubs are 3
162*11efff7fSkettenis      instructions long. */
163*11efff7fSkettenis   insn = read_memory_integer (pc, 4);
164*11efff7fSkettenis 
165*11efff7fSkettenis   /* Find out where we think we are within the stub.  */
166*11efff7fSkettenis   if ((insn & 0xffffc00e) == 0x53610000)
167*11efff7fSkettenis     addr = pc;
168*11efff7fSkettenis   else if ((insn & 0xffffffff) == 0xe820d000)
169*11efff7fSkettenis     addr = pc - 4;
170*11efff7fSkettenis   else if ((insn & 0xffffc00e) == 0x537b0000)
171*11efff7fSkettenis     addr = pc - 8;
172*11efff7fSkettenis   else
173*11efff7fSkettenis     return 0;
174*11efff7fSkettenis 
175*11efff7fSkettenis   /* Now verify each insn in the range looks like a stub instruction.  */
176*11efff7fSkettenis   insn = read_memory_integer (addr, 4);
177*11efff7fSkettenis   if ((insn & 0xffffc00e) != 0x53610000)
178*11efff7fSkettenis     return 0;
179*11efff7fSkettenis 
180*11efff7fSkettenis   /* Now verify each insn in the range looks like a stub instruction.  */
181*11efff7fSkettenis   insn = read_memory_integer (addr + 4, 4);
182*11efff7fSkettenis   if ((insn & 0xffffffff) != 0xe820d000)
183*11efff7fSkettenis     return 0;
184*11efff7fSkettenis 
185*11efff7fSkettenis   /* Now verify each insn in the range looks like a stub instruction.  */
186*11efff7fSkettenis   insn = read_memory_integer (addr + 8, 4);
187*11efff7fSkettenis   if ((insn & 0xffffc00e) != 0x537b0000)
188*11efff7fSkettenis     return 0;
189*11efff7fSkettenis 
190*11efff7fSkettenis   /* Looks like a stub.  */
191*11efff7fSkettenis   return 1;
192*11efff7fSkettenis }
193*11efff7fSkettenis 
194*11efff7fSkettenis /* Return one if PC is in the return path of a trampoline, else return zero.
195*11efff7fSkettenis 
196*11efff7fSkettenis    Note we return one for *any* call trampoline (long-call, arg-reloc), not
197*11efff7fSkettenis    just shared library trampolines (import, export).  */
198*11efff7fSkettenis 
199*11efff7fSkettenis static int
hppa_hpux_in_solib_return_trampoline(CORE_ADDR pc,char * name)200*11efff7fSkettenis hppa_hpux_in_solib_return_trampoline (CORE_ADDR pc, char *name)
201*11efff7fSkettenis {
202*11efff7fSkettenis   struct unwind_table_entry *u;
203*11efff7fSkettenis 
204*11efff7fSkettenis   /* Get the unwind descriptor corresponding to PC, return zero
205*11efff7fSkettenis      if no unwind was found.  */
206*11efff7fSkettenis   u = find_unwind_entry (pc);
207*11efff7fSkettenis   if (!u)
208*11efff7fSkettenis     return 0;
209*11efff7fSkettenis 
210*11efff7fSkettenis   /* If this isn't a linker stub or it's just a long branch stub, then
211*11efff7fSkettenis      return zero.  */
212*11efff7fSkettenis   if (u->stub_unwind.stub_type == 0 || u->stub_unwind.stub_type == LONG_BRANCH)
213*11efff7fSkettenis     return 0;
214*11efff7fSkettenis 
215*11efff7fSkettenis   /* The call and return path execute the same instructions within
216*11efff7fSkettenis      an IMPORT stub!  So an IMPORT stub is both a call and return
217*11efff7fSkettenis      trampoline.  */
218*11efff7fSkettenis   if (u->stub_unwind.stub_type == IMPORT)
219*11efff7fSkettenis     return 1;
220*11efff7fSkettenis 
221*11efff7fSkettenis   /* Parameter relocation stubs always have a call path and may have a
222*11efff7fSkettenis      return path.  */
223*11efff7fSkettenis   if (u->stub_unwind.stub_type == PARAMETER_RELOCATION
224*11efff7fSkettenis       || u->stub_unwind.stub_type == EXPORT)
225*11efff7fSkettenis     {
226*11efff7fSkettenis       CORE_ADDR addr;
227*11efff7fSkettenis 
228*11efff7fSkettenis       /* Search forward from the current PC until we hit a branch
229*11efff7fSkettenis          or the end of the stub.  */
230*11efff7fSkettenis       for (addr = pc; addr <= u->region_end; addr += 4)
231*11efff7fSkettenis 	{
232*11efff7fSkettenis 	  unsigned long insn;
233*11efff7fSkettenis 
234*11efff7fSkettenis 	  insn = read_memory_integer (addr, 4);
235*11efff7fSkettenis 
236*11efff7fSkettenis 	  /* Does it look like a bl?  If so then it's the call path, if
237*11efff7fSkettenis 	     we find a bv or be first, then we're on the return path.  */
238*11efff7fSkettenis 	  if ((insn & 0xfc00e000) == 0xe8000000)
239*11efff7fSkettenis 	    return 0;
240*11efff7fSkettenis 	  else if ((insn & 0xfc00e001) == 0xe800c000
241*11efff7fSkettenis 		   || (insn & 0xfc000000) == 0xe0000000)
242*11efff7fSkettenis 	    return 1;
243*11efff7fSkettenis 	}
244*11efff7fSkettenis 
245*11efff7fSkettenis       /* Should never happen.  */
246*11efff7fSkettenis       warning ("Unable to find branch in parameter relocation stub.\n");
247*11efff7fSkettenis       return 0;
248*11efff7fSkettenis     }
249*11efff7fSkettenis 
250*11efff7fSkettenis   /* Unknown stub type.  For now, just return zero.  */
251*11efff7fSkettenis   return 0;
252*11efff7fSkettenis 
253*11efff7fSkettenis }
254*11efff7fSkettenis 
255*11efff7fSkettenis /* Figure out if PC is in a trampoline, and if so find out where
256*11efff7fSkettenis    the trampoline will jump to.  If not in a trampoline, return zero.
257*11efff7fSkettenis 
258*11efff7fSkettenis    Simple code examination probably is not a good idea since the code
259*11efff7fSkettenis    sequences in trampolines can also appear in user code.
260*11efff7fSkettenis 
261*11efff7fSkettenis    We use unwinds and information from the minimal symbol table to
262*11efff7fSkettenis    determine when we're in a trampoline.  This won't work for ELF
263*11efff7fSkettenis    (yet) since it doesn't create stub unwind entries.  Whether or
264*11efff7fSkettenis    not ELF will create stub unwinds or normal unwinds for linker
265*11efff7fSkettenis    stubs is still being debated.
266*11efff7fSkettenis 
267*11efff7fSkettenis    This should handle simple calls through dyncall or sr4export,
268*11efff7fSkettenis    long calls, argument relocation stubs, and dyncall/sr4export
269*11efff7fSkettenis    calling an argument relocation stub.  It even handles some stubs
270*11efff7fSkettenis    used in dynamic executables.  */
271*11efff7fSkettenis 
272*11efff7fSkettenis static CORE_ADDR
hppa_hpux_skip_trampoline_code(CORE_ADDR pc)273*11efff7fSkettenis hppa_hpux_skip_trampoline_code (CORE_ADDR pc)
274*11efff7fSkettenis {
275*11efff7fSkettenis   long orig_pc = pc;
276*11efff7fSkettenis   long prev_inst, curr_inst, loc;
277*11efff7fSkettenis   struct minimal_symbol *msym;
278*11efff7fSkettenis   struct unwind_table_entry *u;
279*11efff7fSkettenis 
280*11efff7fSkettenis   /* Addresses passed to dyncall may *NOT* be the actual address
281*11efff7fSkettenis      of the function.  So we may have to do something special.  */
282*11efff7fSkettenis   if (pc == hppa_symbol_address("$$dyncall"))
283*11efff7fSkettenis     {
284*11efff7fSkettenis       pc = (CORE_ADDR) read_register (22);
285*11efff7fSkettenis 
286*11efff7fSkettenis       /* If bit 30 (counting from the left) is on, then pc is the address of
287*11efff7fSkettenis          the PLT entry for this function, not the address of the function
288*11efff7fSkettenis          itself.  Bit 31 has meaning too, but only for MPE.  */
289*11efff7fSkettenis       if (pc & 0x2)
290*11efff7fSkettenis 	pc = (CORE_ADDR) read_memory_integer (pc & ~0x3, TARGET_PTR_BIT / 8);
291*11efff7fSkettenis     }
292*11efff7fSkettenis   if (pc == hppa_symbol_address("$$dyncall_external"))
293*11efff7fSkettenis     {
294*11efff7fSkettenis       pc = (CORE_ADDR) read_register (22);
295*11efff7fSkettenis       pc = (CORE_ADDR) read_memory_integer (pc & ~0x3, TARGET_PTR_BIT / 8);
296*11efff7fSkettenis     }
297*11efff7fSkettenis   else if (pc == hppa_symbol_address("_sr4export"))
298*11efff7fSkettenis     pc = (CORE_ADDR) (read_register (22));
299*11efff7fSkettenis 
300*11efff7fSkettenis   /* Get the unwind descriptor corresponding to PC, return zero
301*11efff7fSkettenis      if no unwind was found.  */
302*11efff7fSkettenis   u = find_unwind_entry (pc);
303*11efff7fSkettenis   if (!u)
304*11efff7fSkettenis     return 0;
305*11efff7fSkettenis 
306*11efff7fSkettenis   /* If this isn't a linker stub, then return now.  */
307*11efff7fSkettenis   /* elz: attention here! (FIXME) because of a compiler/linker
308*11efff7fSkettenis      error, some stubs which should have a non zero stub_unwind.stub_type
309*11efff7fSkettenis      have unfortunately a value of zero. So this function would return here
310*11efff7fSkettenis      as if we were not in a trampoline. To fix this, we go look at the partial
311*11efff7fSkettenis      symbol information, which reports this guy as a stub.
312*11efff7fSkettenis      (FIXME): Unfortunately, we are not that lucky: it turns out that the
313*11efff7fSkettenis      partial symbol information is also wrong sometimes. This is because
314*11efff7fSkettenis      when it is entered (somread.c::som_symtab_read()) it can happen that
315*11efff7fSkettenis      if the type of the symbol (from the som) is Entry, and the symbol is
316*11efff7fSkettenis      in a shared library, then it can also be a trampoline.  This would
317*11efff7fSkettenis      be OK, except that I believe the way they decide if we are ina shared library
318*11efff7fSkettenis      does not work. SOOOO..., even if we have a regular function w/o trampolines
319*11efff7fSkettenis      its minimal symbol can be assigned type mst_solib_trampoline.
320*11efff7fSkettenis      Also, if we find that the symbol is a real stub, then we fix the unwind
321*11efff7fSkettenis      descriptor, and define the stub type to be EXPORT.
322*11efff7fSkettenis      Hopefully this is correct most of the times. */
323*11efff7fSkettenis   if (u->stub_unwind.stub_type == 0)
324*11efff7fSkettenis     {
325*11efff7fSkettenis 
326*11efff7fSkettenis /* elz: NOTE (FIXME!) once the problem with the unwind information is fixed
327*11efff7fSkettenis    we can delete all the code which appears between the lines */
328*11efff7fSkettenis /*--------------------------------------------------------------------------*/
329*11efff7fSkettenis       msym = lookup_minimal_symbol_by_pc (pc);
330*11efff7fSkettenis 
331*11efff7fSkettenis       if (msym == NULL || MSYMBOL_TYPE (msym) != mst_solib_trampoline)
332*11efff7fSkettenis 	return orig_pc == pc ? 0 : pc & ~0x3;
333*11efff7fSkettenis 
334*11efff7fSkettenis       else if (msym != NULL && MSYMBOL_TYPE (msym) == mst_solib_trampoline)
335*11efff7fSkettenis 	{
336*11efff7fSkettenis 	  struct objfile *objfile;
337*11efff7fSkettenis 	  struct minimal_symbol *msymbol;
338*11efff7fSkettenis 	  int function_found = 0;
339*11efff7fSkettenis 
340*11efff7fSkettenis 	  /* go look if there is another minimal symbol with the same name as
341*11efff7fSkettenis 	     this one, but with type mst_text. This would happen if the msym
342*11efff7fSkettenis 	     is an actual trampoline, in which case there would be another
343*11efff7fSkettenis 	     symbol with the same name corresponding to the real function */
344*11efff7fSkettenis 
345*11efff7fSkettenis 	  ALL_MSYMBOLS (objfile, msymbol)
346*11efff7fSkettenis 	  {
347*11efff7fSkettenis 	    if (MSYMBOL_TYPE (msymbol) == mst_text
348*11efff7fSkettenis 		&& DEPRECATED_STREQ (DEPRECATED_SYMBOL_NAME (msymbol), DEPRECATED_SYMBOL_NAME (msym)))
349*11efff7fSkettenis 	      {
350*11efff7fSkettenis 		function_found = 1;
351*11efff7fSkettenis 		break;
352*11efff7fSkettenis 	      }
353*11efff7fSkettenis 	  }
354*11efff7fSkettenis 
355*11efff7fSkettenis 	  if (function_found)
356*11efff7fSkettenis 	    /* the type of msym is correct (mst_solib_trampoline), but
357*11efff7fSkettenis 	       the unwind info is wrong, so set it to the correct value */
358*11efff7fSkettenis 	    u->stub_unwind.stub_type = EXPORT;
359*11efff7fSkettenis 	  else
360*11efff7fSkettenis 	    /* the stub type info in the unwind is correct (this is not a
361*11efff7fSkettenis 	       trampoline), but the msym type information is wrong, it
362*11efff7fSkettenis 	       should be mst_text. So we need to fix the msym, and also
363*11efff7fSkettenis 	       get out of this function */
364*11efff7fSkettenis 	    {
365*11efff7fSkettenis 	      MSYMBOL_TYPE (msym) = mst_text;
366*11efff7fSkettenis 	      return orig_pc == pc ? 0 : pc & ~0x3;
367*11efff7fSkettenis 	    }
368*11efff7fSkettenis 	}
369*11efff7fSkettenis 
370*11efff7fSkettenis /*--------------------------------------------------------------------------*/
371*11efff7fSkettenis     }
372*11efff7fSkettenis 
373*11efff7fSkettenis   /* It's a stub.  Search for a branch and figure out where it goes.
374*11efff7fSkettenis      Note we have to handle multi insn branch sequences like ldil;ble.
375*11efff7fSkettenis      Most (all?) other branches can be determined by examining the contents
376*11efff7fSkettenis      of certain registers and the stack.  */
377*11efff7fSkettenis 
378*11efff7fSkettenis   loc = pc;
379*11efff7fSkettenis   curr_inst = 0;
380*11efff7fSkettenis   prev_inst = 0;
381*11efff7fSkettenis   while (1)
382*11efff7fSkettenis     {
383*11efff7fSkettenis       /* Make sure we haven't walked outside the range of this stub.  */
384*11efff7fSkettenis       if (u != find_unwind_entry (loc))
385*11efff7fSkettenis 	{
386*11efff7fSkettenis 	  warning ("Unable to find branch in linker stub");
387*11efff7fSkettenis 	  return orig_pc == pc ? 0 : pc & ~0x3;
388*11efff7fSkettenis 	}
389*11efff7fSkettenis 
390*11efff7fSkettenis       prev_inst = curr_inst;
391*11efff7fSkettenis       curr_inst = read_memory_integer (loc, 4);
392*11efff7fSkettenis 
393*11efff7fSkettenis       /* Does it look like a branch external using %r1?  Then it's the
394*11efff7fSkettenis          branch from the stub to the actual function.  */
395*11efff7fSkettenis       if ((curr_inst & 0xffe0e000) == 0xe0202000)
396*11efff7fSkettenis 	{
397*11efff7fSkettenis 	  /* Yup.  See if the previous instruction loaded
398*11efff7fSkettenis 	     a value into %r1.  If so compute and return the jump address.  */
399*11efff7fSkettenis 	  if ((prev_inst & 0xffe00000) == 0x20200000)
400*11efff7fSkettenis 	    return (hppa_extract_21 (prev_inst) + hppa_extract_17 (curr_inst)) & ~0x3;
401*11efff7fSkettenis 	  else
402*11efff7fSkettenis 	    {
403*11efff7fSkettenis 	      warning ("Unable to find ldil X,%%r1 before ble Y(%%sr4,%%r1).");
404*11efff7fSkettenis 	      return orig_pc == pc ? 0 : pc & ~0x3;
405*11efff7fSkettenis 	    }
406*11efff7fSkettenis 	}
407*11efff7fSkettenis 
408*11efff7fSkettenis       /* Does it look like a be 0(sr0,%r21)? OR
409*11efff7fSkettenis          Does it look like a be, n 0(sr0,%r21)? OR
410*11efff7fSkettenis          Does it look like a bve (r21)? (this is on PA2.0)
411*11efff7fSkettenis          Does it look like a bve, n(r21)? (this is also on PA2.0)
412*11efff7fSkettenis          That's the branch from an
413*11efff7fSkettenis          import stub to an export stub.
414*11efff7fSkettenis 
415*11efff7fSkettenis          It is impossible to determine the target of the branch via
416*11efff7fSkettenis          simple examination of instructions and/or data (consider
417*11efff7fSkettenis          that the address in the plabel may be the address of the
418*11efff7fSkettenis          bind-on-reference routine in the dynamic loader).
419*11efff7fSkettenis 
420*11efff7fSkettenis          So we have try an alternative approach.
421*11efff7fSkettenis 
422*11efff7fSkettenis          Get the name of the symbol at our current location; it should
423*11efff7fSkettenis          be a stub symbol with the same name as the symbol in the
424*11efff7fSkettenis          shared library.
425*11efff7fSkettenis 
426*11efff7fSkettenis          Then lookup a minimal symbol with the same name; we should
427*11efff7fSkettenis          get the minimal symbol for the target routine in the shared
428*11efff7fSkettenis          library as those take precedence of import/export stubs.  */
429*11efff7fSkettenis       if ((curr_inst == 0xe2a00000) ||
430*11efff7fSkettenis 	  (curr_inst == 0xe2a00002) ||
431*11efff7fSkettenis 	  (curr_inst == 0xeaa0d000) ||
432*11efff7fSkettenis 	  (curr_inst == 0xeaa0d002))
433*11efff7fSkettenis 	{
434*11efff7fSkettenis 	  struct minimal_symbol *stubsym, *libsym;
435*11efff7fSkettenis 
436*11efff7fSkettenis 	  stubsym = lookup_minimal_symbol_by_pc (loc);
437*11efff7fSkettenis 	  if (stubsym == NULL)
438*11efff7fSkettenis 	    {
439*11efff7fSkettenis 	      warning ("Unable to find symbol for 0x%lx", loc);
440*11efff7fSkettenis 	      return orig_pc == pc ? 0 : pc & ~0x3;
441*11efff7fSkettenis 	    }
442*11efff7fSkettenis 
443*11efff7fSkettenis 	  libsym = lookup_minimal_symbol (DEPRECATED_SYMBOL_NAME (stubsym), NULL, NULL);
444*11efff7fSkettenis 	  if (libsym == NULL)
445*11efff7fSkettenis 	    {
446*11efff7fSkettenis 	      warning ("Unable to find library symbol for %s\n",
447*11efff7fSkettenis 		       DEPRECATED_SYMBOL_NAME (stubsym));
448*11efff7fSkettenis 	      return orig_pc == pc ? 0 : pc & ~0x3;
449*11efff7fSkettenis 	    }
450*11efff7fSkettenis 
451*11efff7fSkettenis 	  return SYMBOL_VALUE (libsym);
452*11efff7fSkettenis 	}
453*11efff7fSkettenis 
454*11efff7fSkettenis       /* Does it look like bl X,%rp or bl X,%r0?  Another way to do a
455*11efff7fSkettenis          branch from the stub to the actual function.  */
456*11efff7fSkettenis       /*elz */
457*11efff7fSkettenis       else if ((curr_inst & 0xffe0e000) == 0xe8400000
458*11efff7fSkettenis 	       || (curr_inst & 0xffe0e000) == 0xe8000000
459*11efff7fSkettenis 	       || (curr_inst & 0xffe0e000) == 0xe800A000)
460*11efff7fSkettenis 	return (loc + hppa_extract_17 (curr_inst) + 8) & ~0x3;
461*11efff7fSkettenis 
462*11efff7fSkettenis       /* Does it look like bv (rp)?   Note this depends on the
463*11efff7fSkettenis          current stack pointer being the same as the stack
464*11efff7fSkettenis          pointer in the stub itself!  This is a branch on from the
465*11efff7fSkettenis          stub back to the original caller.  */
466*11efff7fSkettenis       /*else if ((curr_inst & 0xffe0e000) == 0xe840c000) */
467*11efff7fSkettenis       else if ((curr_inst & 0xffe0f000) == 0xe840c000)
468*11efff7fSkettenis 	{
469*11efff7fSkettenis 	  /* Yup.  See if the previous instruction loaded
470*11efff7fSkettenis 	     rp from sp - 8.  */
471*11efff7fSkettenis 	  if (prev_inst == 0x4bc23ff1)
472*11efff7fSkettenis 	    return (read_memory_integer
473*11efff7fSkettenis 		    (read_register (HPPA_SP_REGNUM) - 8, 4)) & ~0x3;
474*11efff7fSkettenis 	  else
475*11efff7fSkettenis 	    {
476*11efff7fSkettenis 	      warning ("Unable to find restore of %%rp before bv (%%rp).");
477*11efff7fSkettenis 	      return orig_pc == pc ? 0 : pc & ~0x3;
478*11efff7fSkettenis 	    }
479*11efff7fSkettenis 	}
480*11efff7fSkettenis 
481*11efff7fSkettenis       /* elz: added this case to capture the new instruction
482*11efff7fSkettenis          at the end of the return part of an export stub used by
483*11efff7fSkettenis          the PA2.0: BVE, n (rp) */
484*11efff7fSkettenis       else if ((curr_inst & 0xffe0f000) == 0xe840d000)
485*11efff7fSkettenis 	{
486*11efff7fSkettenis 	  return (read_memory_integer
487*11efff7fSkettenis 		  (read_register (HPPA_SP_REGNUM) - 24, TARGET_PTR_BIT / 8)) & ~0x3;
488*11efff7fSkettenis 	}
489*11efff7fSkettenis 
490*11efff7fSkettenis       /* What about be,n 0(sr0,%rp)?  It's just another way we return to
491*11efff7fSkettenis          the original caller from the stub.  Used in dynamic executables.  */
492*11efff7fSkettenis       else if (curr_inst == 0xe0400002)
493*11efff7fSkettenis 	{
494*11efff7fSkettenis 	  /* The value we jump to is sitting in sp - 24.  But that's
495*11efff7fSkettenis 	     loaded several instructions before the be instruction.
496*11efff7fSkettenis 	     I guess we could check for the previous instruction being
497*11efff7fSkettenis 	     mtsp %r1,%sr0 if we want to do sanity checking.  */
498*11efff7fSkettenis 	  return (read_memory_integer
499*11efff7fSkettenis 		  (read_register (HPPA_SP_REGNUM) - 24, TARGET_PTR_BIT / 8)) & ~0x3;
500*11efff7fSkettenis 	}
501*11efff7fSkettenis 
502*11efff7fSkettenis       /* Haven't found the branch yet, but we're still in the stub.
503*11efff7fSkettenis          Keep looking.  */
504*11efff7fSkettenis       loc += 4;
505*11efff7fSkettenis     }
506*11efff7fSkettenis }
507*11efff7fSkettenis 
508*11efff7fSkettenis 
509*11efff7fSkettenis /* Exception handling support for the HP-UX ANSI C++ compiler.
510*11efff7fSkettenis    The compiler (aCC) provides a callback for exception events;
511*11efff7fSkettenis    GDB can set a breakpoint on this callback and find out what
512*11efff7fSkettenis    exception event has occurred. */
513*11efff7fSkettenis 
514*11efff7fSkettenis /* The name of the hook to be set to point to the callback function */
515*11efff7fSkettenis static char HP_ACC_EH_notify_hook[] = "__eh_notify_hook";
516*11efff7fSkettenis /* The name of the function to be used to set the hook value */
517*11efff7fSkettenis static char HP_ACC_EH_set_hook_value[] = "__eh_set_hook_value";
518*11efff7fSkettenis /* The name of the callback function in end.o */
519*11efff7fSkettenis static char HP_ACC_EH_notify_callback[] = "__d_eh_notify_callback";
520*11efff7fSkettenis /* Name of function in end.o on which a break is set (called by above) */
521*11efff7fSkettenis static char HP_ACC_EH_break[] = "__d_eh_break";
522*11efff7fSkettenis /* Name of flag (in end.o) that enables catching throws */
523*11efff7fSkettenis static char HP_ACC_EH_catch_throw[] = "__d_eh_catch_throw";
524*11efff7fSkettenis /* Name of flag (in end.o) that enables catching catching */
525*11efff7fSkettenis static char HP_ACC_EH_catch_catch[] = "__d_eh_catch_catch";
526*11efff7fSkettenis /* The enum used by aCC */
527*11efff7fSkettenis typedef enum
528*11efff7fSkettenis   {
529*11efff7fSkettenis     __EH_NOTIFY_THROW,
530*11efff7fSkettenis     __EH_NOTIFY_CATCH
531*11efff7fSkettenis   }
532*11efff7fSkettenis __eh_notification;
533*11efff7fSkettenis 
534*11efff7fSkettenis /* Is exception-handling support available with this executable? */
535*11efff7fSkettenis static int hp_cxx_exception_support = 0;
536*11efff7fSkettenis /* Has the initialize function been run? */
537*11efff7fSkettenis static int hp_cxx_exception_support_initialized = 0;
538*11efff7fSkettenis /* Address of __eh_notify_hook */
539*11efff7fSkettenis static CORE_ADDR eh_notify_hook_addr = 0;
540*11efff7fSkettenis /* Address of __d_eh_notify_callback */
541*11efff7fSkettenis static CORE_ADDR eh_notify_callback_addr = 0;
542*11efff7fSkettenis /* Address of __d_eh_break */
543*11efff7fSkettenis static CORE_ADDR eh_break_addr = 0;
544*11efff7fSkettenis /* Address of __d_eh_catch_catch */
545*11efff7fSkettenis static CORE_ADDR eh_catch_catch_addr = 0;
546*11efff7fSkettenis /* Address of __d_eh_catch_throw */
547*11efff7fSkettenis static CORE_ADDR eh_catch_throw_addr = 0;
548*11efff7fSkettenis /* Sal for __d_eh_break */
549*11efff7fSkettenis static struct symtab_and_line *break_callback_sal = 0;
550*11efff7fSkettenis 
551*11efff7fSkettenis /* Code in end.c expects __d_pid to be set in the inferior,
552*11efff7fSkettenis    otherwise __d_eh_notify_callback doesn't bother to call
553*11efff7fSkettenis    __d_eh_break!  So we poke the pid into this symbol
554*11efff7fSkettenis    ourselves.
555*11efff7fSkettenis    0 => success
556*11efff7fSkettenis    1 => failure  */
557b725ae77Skettenis int
setup_d_pid_in_inferior(void)558*11efff7fSkettenis setup_d_pid_in_inferior (void)
559b725ae77Skettenis {
560*11efff7fSkettenis   CORE_ADDR anaddr;
561*11efff7fSkettenis   struct minimal_symbol *msymbol;
562*11efff7fSkettenis   char buf[4];			/* FIXME 32x64? */
563*11efff7fSkettenis 
564*11efff7fSkettenis   /* Slam the pid of the process into __d_pid; failing is only a warning!  */
565*11efff7fSkettenis   msymbol = lookup_minimal_symbol ("__d_pid", NULL, symfile_objfile);
566*11efff7fSkettenis   if (msymbol == NULL)
567*11efff7fSkettenis     {
568*11efff7fSkettenis       warning ("Unable to find __d_pid symbol in object file.");
569*11efff7fSkettenis       warning ("Suggest linking executable with -g (links in /opt/langtools/lib/end.o).");
570*11efff7fSkettenis       return 1;
571b725ae77Skettenis     }
572b725ae77Skettenis 
573*11efff7fSkettenis   anaddr = SYMBOL_VALUE_ADDRESS (msymbol);
574*11efff7fSkettenis   store_unsigned_integer (buf, 4, PIDGET (inferior_ptid)); /* FIXME 32x64? */
575*11efff7fSkettenis   if (target_write_memory (anaddr, buf, 4))	/* FIXME 32x64? */
576b725ae77Skettenis     {
577*11efff7fSkettenis       warning ("Unable to write __d_pid");
578*11efff7fSkettenis       warning ("Suggest linking executable with -g (links in /opt/langtools/lib/end.o).");
579*11efff7fSkettenis       return 1;
580*11efff7fSkettenis     }
581*11efff7fSkettenis   return 0;
582b725ae77Skettenis }
583b725ae77Skettenis 
584*11efff7fSkettenis /* elz: Used to lookup a symbol in the shared libraries.
585*11efff7fSkettenis    This function calls shl_findsym, indirectly through a
586*11efff7fSkettenis    call to __d_shl_get. __d_shl_get is in end.c, which is always
587*11efff7fSkettenis    linked in by the hp compilers/linkers.
588*11efff7fSkettenis    The call to shl_findsym cannot be made directly because it needs
589*11efff7fSkettenis    to be active in target address space.
590*11efff7fSkettenis    inputs: - minimal symbol pointer for the function we want to look up
591*11efff7fSkettenis    - address in target space of the descriptor for the library
592*11efff7fSkettenis    where we want to look the symbol up.
593*11efff7fSkettenis    This address is retrieved using the
594*11efff7fSkettenis    som_solib_get_solib_by_pc function (somsolib.c).
595*11efff7fSkettenis    output: - real address in the library of the function.
596*11efff7fSkettenis    note: the handle can be null, in which case shl_findsym will look for
597*11efff7fSkettenis    the symbol in all the loaded shared libraries.
598*11efff7fSkettenis    files to look at if you need reference on this stuff:
599*11efff7fSkettenis    dld.c, dld_shl_findsym.c
600*11efff7fSkettenis    end.c
601*11efff7fSkettenis    man entry for shl_findsym */
602*11efff7fSkettenis 
603*11efff7fSkettenis CORE_ADDR
find_stub_with_shl_get(struct minimal_symbol * function,CORE_ADDR handle)604*11efff7fSkettenis find_stub_with_shl_get (struct minimal_symbol *function, CORE_ADDR handle)
605b725ae77Skettenis {
606*11efff7fSkettenis   struct symbol *get_sym, *symbol2;
607*11efff7fSkettenis   struct minimal_symbol *buff_minsym, *msymbol;
608*11efff7fSkettenis   struct type *ftype;
609*11efff7fSkettenis   struct value **args;
610*11efff7fSkettenis   struct value *funcval;
611*11efff7fSkettenis   struct value *val;
612*11efff7fSkettenis 
613*11efff7fSkettenis   int x, namelen, err_value, tmp = -1;
614*11efff7fSkettenis   CORE_ADDR endo_buff_addr, value_return_addr, errno_return_addr;
615*11efff7fSkettenis   CORE_ADDR stub_addr;
616*11efff7fSkettenis 
617*11efff7fSkettenis 
618*11efff7fSkettenis   args = alloca (sizeof (struct value *) * 8);		/* 6 for the arguments and one null one??? */
619*11efff7fSkettenis   funcval = find_function_in_inferior ("__d_shl_get");
620*11efff7fSkettenis   get_sym = lookup_symbol ("__d_shl_get", NULL, VAR_DOMAIN, NULL, NULL);
621*11efff7fSkettenis   buff_minsym = lookup_minimal_symbol ("__buffer", NULL, NULL);
622*11efff7fSkettenis   msymbol = lookup_minimal_symbol ("__shldp", NULL, NULL);
623*11efff7fSkettenis   symbol2 = lookup_symbol ("__shldp", NULL, VAR_DOMAIN, NULL, NULL);
624*11efff7fSkettenis   endo_buff_addr = SYMBOL_VALUE_ADDRESS (buff_minsym);
625*11efff7fSkettenis   namelen = strlen (DEPRECATED_SYMBOL_NAME (function));
626*11efff7fSkettenis   value_return_addr = endo_buff_addr + namelen;
627*11efff7fSkettenis   ftype = check_typedef (SYMBOL_TYPE (get_sym));
628*11efff7fSkettenis 
629*11efff7fSkettenis   /* do alignment */
630*11efff7fSkettenis   if ((x = value_return_addr % 64) != 0)
631*11efff7fSkettenis     value_return_addr = value_return_addr + 64 - x;
632*11efff7fSkettenis 
633*11efff7fSkettenis   errno_return_addr = value_return_addr + 64;
634*11efff7fSkettenis 
635*11efff7fSkettenis 
636*11efff7fSkettenis   /* set up stuff needed by __d_shl_get in buffer in end.o */
637*11efff7fSkettenis 
638*11efff7fSkettenis   target_write_memory (endo_buff_addr, DEPRECATED_SYMBOL_NAME (function), namelen);
639*11efff7fSkettenis 
640*11efff7fSkettenis   target_write_memory (value_return_addr, (char *) &tmp, 4);
641*11efff7fSkettenis 
642*11efff7fSkettenis   target_write_memory (errno_return_addr, (char *) &tmp, 4);
643*11efff7fSkettenis 
644*11efff7fSkettenis   target_write_memory (SYMBOL_VALUE_ADDRESS (msymbol),
645*11efff7fSkettenis 		       (char *) &handle, 4);
646*11efff7fSkettenis 
647*11efff7fSkettenis   /* now prepare the arguments for the call */
648*11efff7fSkettenis 
649*11efff7fSkettenis   args[0] = value_from_longest (TYPE_FIELD_TYPE (ftype, 0), 12);
650*11efff7fSkettenis   args[1] = value_from_pointer (TYPE_FIELD_TYPE (ftype, 1), SYMBOL_VALUE_ADDRESS (msymbol));
651*11efff7fSkettenis   args[2] = value_from_pointer (TYPE_FIELD_TYPE (ftype, 2), endo_buff_addr);
652*11efff7fSkettenis   args[3] = value_from_longest (TYPE_FIELD_TYPE (ftype, 3), TYPE_PROCEDURE);
653*11efff7fSkettenis   args[4] = value_from_pointer (TYPE_FIELD_TYPE (ftype, 4), value_return_addr);
654*11efff7fSkettenis   args[5] = value_from_pointer (TYPE_FIELD_TYPE (ftype, 5), errno_return_addr);
655*11efff7fSkettenis 
656*11efff7fSkettenis   /* now call the function */
657*11efff7fSkettenis 
658*11efff7fSkettenis   val = call_function_by_hand (funcval, 6, args);
659*11efff7fSkettenis 
660*11efff7fSkettenis   /* now get the results */
661*11efff7fSkettenis 
662*11efff7fSkettenis   target_read_memory (errno_return_addr, (char *) &err_value, sizeof (err_value));
663*11efff7fSkettenis 
664*11efff7fSkettenis   target_read_memory (value_return_addr, (char *) &stub_addr, sizeof (stub_addr));
665*11efff7fSkettenis   if (stub_addr <= 0)
666*11efff7fSkettenis     error ("call to __d_shl_get failed, error code is %d", err_value);
667*11efff7fSkettenis 
668*11efff7fSkettenis   return (stub_addr);
669b725ae77Skettenis }
670b725ae77Skettenis 
671*11efff7fSkettenis /* Cover routine for find_stub_with_shl_get to pass to catch_errors */
672*11efff7fSkettenis static int
cover_find_stub_with_shl_get(void * args_untyped)673*11efff7fSkettenis cover_find_stub_with_shl_get (void *args_untyped)
674b725ae77Skettenis {
675*11efff7fSkettenis   args_for_find_stub *args = args_untyped;
676*11efff7fSkettenis   args->return_val = find_stub_with_shl_get (args->msym, args->solib_handle);
677*11efff7fSkettenis   return 0;
678*11efff7fSkettenis }
679*11efff7fSkettenis 
680*11efff7fSkettenis /* Initialize exception catchpoint support by looking for the
681*11efff7fSkettenis    necessary hooks/callbacks in end.o, etc., and set the hook value to
682*11efff7fSkettenis    point to the required debug function
683*11efff7fSkettenis 
684*11efff7fSkettenis    Return 0 => failure
685*11efff7fSkettenis    1 => success          */
686*11efff7fSkettenis 
687*11efff7fSkettenis static int
initialize_hp_cxx_exception_support(void)688*11efff7fSkettenis initialize_hp_cxx_exception_support (void)
689*11efff7fSkettenis {
690*11efff7fSkettenis   struct symtabs_and_lines sals;
691*11efff7fSkettenis   struct cleanup *old_chain;
692*11efff7fSkettenis   struct cleanup *canonical_strings_chain = NULL;
693b725ae77Skettenis   int i;
694*11efff7fSkettenis   char *addr_start;
695*11efff7fSkettenis   char *addr_end = NULL;
696*11efff7fSkettenis   char **canonical = (char **) NULL;
697*11efff7fSkettenis   int thread = -1;
698*11efff7fSkettenis   struct symbol *sym = NULL;
699*11efff7fSkettenis   struct minimal_symbol *msym = NULL;
700*11efff7fSkettenis   struct objfile *objfile;
701*11efff7fSkettenis   asection *shlib_info;
702b725ae77Skettenis 
703*11efff7fSkettenis   /* Detect and disallow recursion.  On HP-UX with aCC, infinite
704*11efff7fSkettenis      recursion is a possibility because finding the hook for exception
705*11efff7fSkettenis      callbacks involves making a call in the inferior, which means
706*11efff7fSkettenis      re-inserting breakpoints which can re-invoke this code */
707*11efff7fSkettenis 
708*11efff7fSkettenis   static int recurse = 0;
709*11efff7fSkettenis   if (recurse > 0)
710b725ae77Skettenis     {
711*11efff7fSkettenis       hp_cxx_exception_support_initialized = 0;
712*11efff7fSkettenis       deprecated_exception_support_initialized = 0;
713*11efff7fSkettenis       return 0;
714*11efff7fSkettenis     }
715*11efff7fSkettenis 
716*11efff7fSkettenis   hp_cxx_exception_support = 0;
717*11efff7fSkettenis 
718*11efff7fSkettenis   /* First check if we have seen any HP compiled objects; if not,
719*11efff7fSkettenis      it is very unlikely that HP's idiosyncratic callback mechanism
720*11efff7fSkettenis      for exception handling debug support will be available!
721*11efff7fSkettenis      This will percolate back up to breakpoint.c, where our callers
722*11efff7fSkettenis      will decide to try the g++ exception-handling support instead. */
723*11efff7fSkettenis   if (!deprecated_hp_som_som_object_present)
724*11efff7fSkettenis     return 0;
725*11efff7fSkettenis 
726*11efff7fSkettenis   /* We have a SOM executable with SOM debug info; find the hooks */
727*11efff7fSkettenis 
728*11efff7fSkettenis   /* First look for the notify hook provided by aCC runtime libs */
729*11efff7fSkettenis   /* If we find this symbol, we conclude that the executable must
730*11efff7fSkettenis      have HP aCC exception support built in.  If this symbol is not
731*11efff7fSkettenis      found, even though we're a HP SOM-SOM file, we may have been
732*11efff7fSkettenis      built with some other compiler (not aCC).  This results percolates
733*11efff7fSkettenis      back up to our callers in breakpoint.c which can decide to
734*11efff7fSkettenis      try the g++ style of exception support instead.
735*11efff7fSkettenis      If this symbol is found but the other symbols we require are
736*11efff7fSkettenis      not found, there is something weird going on, and g++ support
737*11efff7fSkettenis      should *not* be tried as an alternative.
738*11efff7fSkettenis 
739*11efff7fSkettenis      ASSUMPTION: Only HP aCC code will have __eh_notify_hook defined.
740*11efff7fSkettenis      ASSUMPTION: HP aCC and g++ modules cannot be linked together. */
741*11efff7fSkettenis 
742*11efff7fSkettenis   /* libCsup has this hook; it'll usually be non-debuggable */
743*11efff7fSkettenis   msym = lookup_minimal_symbol (HP_ACC_EH_notify_hook, NULL, NULL);
744*11efff7fSkettenis   if (msym)
745*11efff7fSkettenis     {
746*11efff7fSkettenis       eh_notify_hook_addr = SYMBOL_VALUE_ADDRESS (msym);
747*11efff7fSkettenis       hp_cxx_exception_support = 1;
748*11efff7fSkettenis     }
749b725ae77Skettenis   else
750*11efff7fSkettenis     {
751*11efff7fSkettenis       warning ("Unable to find exception callback hook (%s).", HP_ACC_EH_notify_hook);
752*11efff7fSkettenis       warning ("Executable may not have been compiled debuggable with HP aCC.");
753*11efff7fSkettenis       warning ("GDB will be unable to intercept exception events.");
754*11efff7fSkettenis       eh_notify_hook_addr = 0;
755*11efff7fSkettenis       hp_cxx_exception_support = 0;
756*11efff7fSkettenis       return 0;
757b725ae77Skettenis     }
758b725ae77Skettenis 
759*11efff7fSkettenis   /* Next look for the notify callback routine in end.o */
760*11efff7fSkettenis   /* This is always available in the SOM symbol dictionary if end.o is linked in */
761*11efff7fSkettenis   msym = lookup_minimal_symbol (HP_ACC_EH_notify_callback, NULL, NULL);
762*11efff7fSkettenis   if (msym)
763b725ae77Skettenis     {
764*11efff7fSkettenis       eh_notify_callback_addr = SYMBOL_VALUE_ADDRESS (msym);
765*11efff7fSkettenis       hp_cxx_exception_support = 1;
766b725ae77Skettenis     }
767b725ae77Skettenis   else
768*11efff7fSkettenis     {
769*11efff7fSkettenis       warning ("Unable to find exception callback routine (%s).", HP_ACC_EH_notify_callback);
770*11efff7fSkettenis       warning ("Suggest linking executable with -g (links in /opt/langtools/lib/end.o).");
771*11efff7fSkettenis       warning ("GDB will be unable to intercept exception events.");
772*11efff7fSkettenis       eh_notify_callback_addr = 0;
773*11efff7fSkettenis       return 0;
774b725ae77Skettenis     }
775*11efff7fSkettenis 
776*11efff7fSkettenis #ifndef GDB_TARGET_IS_HPPA_20W
777*11efff7fSkettenis   /* Check whether the executable is dynamically linked or archive bound */
778*11efff7fSkettenis   /* With an archive-bound executable we can use the raw addresses we find
779*11efff7fSkettenis      for the callback function, etc. without modification. For an executable
780*11efff7fSkettenis      with shared libraries, we have to do more work to find the plabel, which
781*11efff7fSkettenis      can be the target of a call through $$dyncall from the aCC runtime support
782*11efff7fSkettenis      library (libCsup) which is linked shared by default by aCC. */
783*11efff7fSkettenis   /* This test below was copied from somsolib.c/somread.c.  It may not be a very
784*11efff7fSkettenis      reliable one to test that an executable is linked shared. pai/1997-07-18 */
785*11efff7fSkettenis   shlib_info = bfd_get_section_by_name (symfile_objfile->obfd, "$SHLIB_INFO$");
786*11efff7fSkettenis   if (shlib_info && (bfd_section_size (symfile_objfile->obfd, shlib_info) != 0))
787*11efff7fSkettenis     {
788*11efff7fSkettenis       /* The minsym we have has the local code address, but that's not the
789*11efff7fSkettenis          plabel that can be used by an inter-load-module call. */
790*11efff7fSkettenis       /* Find solib handle for main image (which has end.o), and use that
791*11efff7fSkettenis          and the min sym as arguments to __d_shl_get() (which does the equivalent
792*11efff7fSkettenis          of shl_findsym()) to find the plabel. */
793*11efff7fSkettenis 
794*11efff7fSkettenis       args_for_find_stub args;
795*11efff7fSkettenis       static char message[] = "Error while finding exception callback hook:\n";
796*11efff7fSkettenis 
797*11efff7fSkettenis       args.solib_handle = som_solib_get_solib_by_pc (eh_notify_callback_addr);
798*11efff7fSkettenis       args.msym = msym;
799*11efff7fSkettenis       args.return_val = 0;
800*11efff7fSkettenis 
801*11efff7fSkettenis       recurse++;
802*11efff7fSkettenis       catch_errors (cover_find_stub_with_shl_get, &args, message,
803*11efff7fSkettenis 		    RETURN_MASK_ALL);
804*11efff7fSkettenis       eh_notify_callback_addr = args.return_val;
805*11efff7fSkettenis       recurse--;
806*11efff7fSkettenis 
807*11efff7fSkettenis       deprecated_exception_catchpoints_are_fragile = 1;
808*11efff7fSkettenis 
809*11efff7fSkettenis       if (!eh_notify_callback_addr)
810*11efff7fSkettenis 	{
811*11efff7fSkettenis 	  /* We can get here either if there is no plabel in the export list
812*11efff7fSkettenis 	     for the main image, or if something strange happened (?) */
813*11efff7fSkettenis 	  warning ("Couldn't find a plabel (indirect function label) for the exception callback.");
814*11efff7fSkettenis 	  warning ("GDB will not be able to intercept exception events.");
815*11efff7fSkettenis 	  return 0;
816*11efff7fSkettenis 	}
817*11efff7fSkettenis     }
818*11efff7fSkettenis   else
819*11efff7fSkettenis     deprecated_exception_catchpoints_are_fragile = 0;
820*11efff7fSkettenis #endif
821*11efff7fSkettenis 
822*11efff7fSkettenis   /* Now, look for the breakpointable routine in end.o */
823*11efff7fSkettenis   /* This should also be available in the SOM symbol dict. if end.o linked in */
824*11efff7fSkettenis   msym = lookup_minimal_symbol (HP_ACC_EH_break, NULL, NULL);
825*11efff7fSkettenis   if (msym)
826*11efff7fSkettenis     {
827*11efff7fSkettenis       eh_break_addr = SYMBOL_VALUE_ADDRESS (msym);
828*11efff7fSkettenis       hp_cxx_exception_support = 1;
829*11efff7fSkettenis     }
830*11efff7fSkettenis   else
831*11efff7fSkettenis     {
832*11efff7fSkettenis       warning ("Unable to find exception callback routine to set breakpoint (%s).", HP_ACC_EH_break);
833*11efff7fSkettenis       warning ("Suggest linking executable with -g (link in /opt/langtools/lib/end.o).");
834*11efff7fSkettenis       warning ("GDB will be unable to intercept exception events.");
835*11efff7fSkettenis       eh_break_addr = 0;
836*11efff7fSkettenis       return 0;
837*11efff7fSkettenis     }
838*11efff7fSkettenis 
839*11efff7fSkettenis   /* Next look for the catch enable flag provided in end.o */
840*11efff7fSkettenis   sym = lookup_symbol (HP_ACC_EH_catch_catch, (struct block *) NULL,
841*11efff7fSkettenis 		       VAR_DOMAIN, 0, (struct symtab **) NULL);
842*11efff7fSkettenis   if (sym)			/* sometimes present in debug info */
843*11efff7fSkettenis     {
844*11efff7fSkettenis       eh_catch_catch_addr = SYMBOL_VALUE_ADDRESS (sym);
845*11efff7fSkettenis       hp_cxx_exception_support = 1;
846*11efff7fSkettenis     }
847*11efff7fSkettenis   else
848*11efff7fSkettenis     /* otherwise look in SOM symbol dict. */
849*11efff7fSkettenis     {
850*11efff7fSkettenis       msym = lookup_minimal_symbol (HP_ACC_EH_catch_catch, NULL, NULL);
851*11efff7fSkettenis       if (msym)
852*11efff7fSkettenis 	{
853*11efff7fSkettenis 	  eh_catch_catch_addr = SYMBOL_VALUE_ADDRESS (msym);
854*11efff7fSkettenis 	  hp_cxx_exception_support = 1;
855*11efff7fSkettenis 	}
856*11efff7fSkettenis       else
857*11efff7fSkettenis 	{
858*11efff7fSkettenis 	  warning ("Unable to enable interception of exception catches.");
859*11efff7fSkettenis 	  warning ("Executable may not have been compiled debuggable with HP aCC.");
860*11efff7fSkettenis 	  warning ("Suggest linking executable with -g (link in /opt/langtools/lib/end.o).");
861*11efff7fSkettenis 	  return 0;
862*11efff7fSkettenis 	}
863*11efff7fSkettenis     }
864*11efff7fSkettenis 
865*11efff7fSkettenis   /* Next look for the catch enable flag provided end.o */
866*11efff7fSkettenis   sym = lookup_symbol (HP_ACC_EH_catch_catch, (struct block *) NULL,
867*11efff7fSkettenis 		       VAR_DOMAIN, 0, (struct symtab **) NULL);
868*11efff7fSkettenis   if (sym)			/* sometimes present in debug info */
869*11efff7fSkettenis     {
870*11efff7fSkettenis       eh_catch_throw_addr = SYMBOL_VALUE_ADDRESS (sym);
871*11efff7fSkettenis       hp_cxx_exception_support = 1;
872*11efff7fSkettenis     }
873*11efff7fSkettenis   else
874*11efff7fSkettenis     /* otherwise look in SOM symbol dict. */
875*11efff7fSkettenis     {
876*11efff7fSkettenis       msym = lookup_minimal_symbol (HP_ACC_EH_catch_throw, NULL, NULL);
877*11efff7fSkettenis       if (msym)
878*11efff7fSkettenis 	{
879*11efff7fSkettenis 	  eh_catch_throw_addr = SYMBOL_VALUE_ADDRESS (msym);
880*11efff7fSkettenis 	  hp_cxx_exception_support = 1;
881*11efff7fSkettenis 	}
882*11efff7fSkettenis       else
883*11efff7fSkettenis 	{
884*11efff7fSkettenis 	  warning ("Unable to enable interception of exception throws.");
885*11efff7fSkettenis 	  warning ("Executable may not have been compiled debuggable with HP aCC.");
886*11efff7fSkettenis 	  warning ("Suggest linking executable with -g (link in /opt/langtools/lib/end.o).");
887*11efff7fSkettenis 	  return 0;
888*11efff7fSkettenis 	}
889*11efff7fSkettenis     }
890*11efff7fSkettenis 
891*11efff7fSkettenis   /* Set the flags */
892*11efff7fSkettenis   hp_cxx_exception_support = 2;	/* everything worked so far */
893*11efff7fSkettenis   hp_cxx_exception_support_initialized = 1;
894*11efff7fSkettenis   deprecated_exception_support_initialized = 1;
895*11efff7fSkettenis 
896*11efff7fSkettenis   return 1;
897*11efff7fSkettenis }
898*11efff7fSkettenis 
899*11efff7fSkettenis /* Target operation for enabling or disabling interception of
900*11efff7fSkettenis    exception events.
901*11efff7fSkettenis    KIND is either EX_EVENT_THROW or EX_EVENT_CATCH
902*11efff7fSkettenis    ENABLE is either 0 (disable) or 1 (enable).
903*11efff7fSkettenis    Return value is NULL if no support found;
904*11efff7fSkettenis    -1 if something went wrong,
905*11efff7fSkettenis    or a pointer to a symtab/line struct if the breakpointable
906*11efff7fSkettenis    address was found. */
907*11efff7fSkettenis 
908*11efff7fSkettenis struct symtab_and_line *
child_enable_exception_callback(enum exception_event_kind kind,int enable)909*11efff7fSkettenis child_enable_exception_callback (enum exception_event_kind kind, int enable)
910*11efff7fSkettenis {
911*11efff7fSkettenis   char buf[4];
912*11efff7fSkettenis 
913*11efff7fSkettenis   if (!deprecated_exception_support_initialized
914*11efff7fSkettenis       || !hp_cxx_exception_support_initialized)
915*11efff7fSkettenis     if (!initialize_hp_cxx_exception_support ())
916*11efff7fSkettenis       return NULL;
917*11efff7fSkettenis 
918*11efff7fSkettenis   switch (hp_cxx_exception_support)
919*11efff7fSkettenis     {
920*11efff7fSkettenis     case 0:
921*11efff7fSkettenis       /* Assuming no HP support at all */
922*11efff7fSkettenis       return NULL;
923*11efff7fSkettenis     case 1:
924*11efff7fSkettenis       /* HP support should be present, but something went wrong */
925*11efff7fSkettenis       return (struct symtab_and_line *) -1;	/* yuck! */
926*11efff7fSkettenis       /* there may be other cases in the future */
927*11efff7fSkettenis     }
928*11efff7fSkettenis 
929*11efff7fSkettenis   /* Set the EH hook to point to the callback routine */
930*11efff7fSkettenis   store_unsigned_integer (buf, 4, enable ? eh_notify_callback_addr : 0);	/* FIXME 32x64 problem */
931*11efff7fSkettenis   /* pai: (temp) FIXME should there be a pack operation first? */
932*11efff7fSkettenis   if (target_write_memory (eh_notify_hook_addr, buf, 4))	/* FIXME 32x64 problem */
933*11efff7fSkettenis     {
934*11efff7fSkettenis       warning ("Could not write to target memory for exception event callback.");
935*11efff7fSkettenis       warning ("Interception of exception events may not work.");
936*11efff7fSkettenis       return (struct symtab_and_line *) -1;
937*11efff7fSkettenis     }
938*11efff7fSkettenis   if (enable)
939*11efff7fSkettenis     {
940*11efff7fSkettenis       /* Ensure that __d_pid is set up correctly -- end.c code checks this. :-( */
941*11efff7fSkettenis       if (PIDGET (inferior_ptid) > 0)
942*11efff7fSkettenis 	{
943*11efff7fSkettenis 	  if (setup_d_pid_in_inferior ())
944*11efff7fSkettenis 	    return (struct symtab_and_line *) -1;
945*11efff7fSkettenis 	}
946*11efff7fSkettenis       else
947*11efff7fSkettenis 	{
948*11efff7fSkettenis 	  warning ("Internal error: Invalid inferior pid?  Cannot intercept exception events.");
949*11efff7fSkettenis 	  return (struct symtab_and_line *) -1;
950*11efff7fSkettenis 	}
951*11efff7fSkettenis     }
952*11efff7fSkettenis 
953*11efff7fSkettenis   switch (kind)
954*11efff7fSkettenis     {
955*11efff7fSkettenis     case EX_EVENT_THROW:
956*11efff7fSkettenis       store_unsigned_integer (buf, 4, enable ? 1 : 0);
957*11efff7fSkettenis       if (target_write_memory (eh_catch_throw_addr, buf, 4))	/* FIXME 32x64? */
958*11efff7fSkettenis 	{
959*11efff7fSkettenis 	  warning ("Couldn't enable exception throw interception.");
960*11efff7fSkettenis 	  return (struct symtab_and_line *) -1;
961*11efff7fSkettenis 	}
962*11efff7fSkettenis       break;
963*11efff7fSkettenis     case EX_EVENT_CATCH:
964*11efff7fSkettenis       store_unsigned_integer (buf, 4, enable ? 1 : 0);
965*11efff7fSkettenis       if (target_write_memory (eh_catch_catch_addr, buf, 4))	/* FIXME 32x64? */
966*11efff7fSkettenis 	{
967*11efff7fSkettenis 	  warning ("Couldn't enable exception catch interception.");
968*11efff7fSkettenis 	  return (struct symtab_and_line *) -1;
969*11efff7fSkettenis 	}
970*11efff7fSkettenis       break;
971*11efff7fSkettenis     default:
972*11efff7fSkettenis       error ("Request to enable unknown or unsupported exception event.");
973*11efff7fSkettenis     }
974*11efff7fSkettenis 
975*11efff7fSkettenis   /* Copy break address into new sal struct, malloc'ing if needed. */
976*11efff7fSkettenis   if (!break_callback_sal)
977*11efff7fSkettenis     {
978*11efff7fSkettenis       break_callback_sal = (struct symtab_and_line *) xmalloc (sizeof (struct symtab_and_line));
979*11efff7fSkettenis     }
980*11efff7fSkettenis   init_sal (break_callback_sal);
981*11efff7fSkettenis   break_callback_sal->symtab = NULL;
982*11efff7fSkettenis   break_callback_sal->pc = eh_break_addr;
983*11efff7fSkettenis   break_callback_sal->line = 0;
984*11efff7fSkettenis   break_callback_sal->end = eh_break_addr;
985*11efff7fSkettenis 
986*11efff7fSkettenis   return break_callback_sal;
987*11efff7fSkettenis }
988*11efff7fSkettenis 
989*11efff7fSkettenis /* Record some information about the current exception event */
990*11efff7fSkettenis static struct exception_event_record current_ex_event;
991*11efff7fSkettenis /* Convenience struct */
992*11efff7fSkettenis static struct symtab_and_line null_symtab_and_line =
993*11efff7fSkettenis {NULL, 0, 0, 0};
994*11efff7fSkettenis 
995*11efff7fSkettenis /* Report current exception event.  Returns a pointer to a record
996*11efff7fSkettenis    that describes the kind of the event, where it was thrown from,
997*11efff7fSkettenis    and where it will be caught.  More information may be reported
998*11efff7fSkettenis    in the future */
999*11efff7fSkettenis struct exception_event_record *
child_get_current_exception_event(void)1000*11efff7fSkettenis child_get_current_exception_event (void)
1001*11efff7fSkettenis {
1002*11efff7fSkettenis   CORE_ADDR event_kind;
1003*11efff7fSkettenis   CORE_ADDR throw_addr;
1004*11efff7fSkettenis   CORE_ADDR catch_addr;
1005*11efff7fSkettenis   struct frame_info *fi, *curr_frame;
1006*11efff7fSkettenis   int level = 1;
1007*11efff7fSkettenis 
1008*11efff7fSkettenis   curr_frame = get_current_frame ();
1009*11efff7fSkettenis   if (!curr_frame)
1010*11efff7fSkettenis     return (struct exception_event_record *) NULL;
1011*11efff7fSkettenis 
1012*11efff7fSkettenis   /* Go up one frame to __d_eh_notify_callback, because at the
1013*11efff7fSkettenis      point when this code is executed, there's garbage in the
1014*11efff7fSkettenis      arguments of __d_eh_break. */
1015*11efff7fSkettenis   fi = find_relative_frame (curr_frame, &level);
1016*11efff7fSkettenis   if (level != 0)
1017*11efff7fSkettenis     return (struct exception_event_record *) NULL;
1018*11efff7fSkettenis 
1019*11efff7fSkettenis   select_frame (fi);
1020*11efff7fSkettenis 
1021*11efff7fSkettenis   /* Read in the arguments */
1022*11efff7fSkettenis   /* __d_eh_notify_callback() is called with 3 arguments:
1023*11efff7fSkettenis      1. event kind catch or throw
1024*11efff7fSkettenis      2. the target address if known
1025*11efff7fSkettenis      3. a flag -- not sure what this is. pai/1997-07-17 */
1026*11efff7fSkettenis   event_kind = read_register (HPPA_ARG0_REGNUM);
1027*11efff7fSkettenis   catch_addr = read_register (HPPA_ARG1_REGNUM);
1028*11efff7fSkettenis 
1029*11efff7fSkettenis   /* Now go down to a user frame */
1030*11efff7fSkettenis   /* For a throw, __d_eh_break is called by
1031*11efff7fSkettenis      __d_eh_notify_callback which is called by
1032*11efff7fSkettenis      __notify_throw which is called
1033*11efff7fSkettenis      from user code.
1034*11efff7fSkettenis      For a catch, __d_eh_break is called by
1035*11efff7fSkettenis      __d_eh_notify_callback which is called by
1036*11efff7fSkettenis      <stackwalking stuff> which is called by
1037*11efff7fSkettenis      __throw__<stuff> or __rethrow_<stuff> which is called
1038*11efff7fSkettenis      from user code. */
1039*11efff7fSkettenis   /* FIXME: Don't use such magic numbers; search for the frames */
1040*11efff7fSkettenis   level = (event_kind == EX_EVENT_THROW) ? 3 : 4;
1041*11efff7fSkettenis   fi = find_relative_frame (curr_frame, &level);
1042*11efff7fSkettenis   if (level != 0)
1043*11efff7fSkettenis     return (struct exception_event_record *) NULL;
1044*11efff7fSkettenis 
1045*11efff7fSkettenis   select_frame (fi);
1046*11efff7fSkettenis   throw_addr = get_frame_pc (fi);
1047*11efff7fSkettenis 
1048*11efff7fSkettenis   /* Go back to original (top) frame */
1049*11efff7fSkettenis   select_frame (curr_frame);
1050*11efff7fSkettenis 
1051*11efff7fSkettenis   current_ex_event.kind = (enum exception_event_kind) event_kind;
1052*11efff7fSkettenis   current_ex_event.throw_sal = find_pc_line (throw_addr, 1);
1053*11efff7fSkettenis   current_ex_event.catch_sal = find_pc_line (catch_addr, 1);
1054*11efff7fSkettenis 
1055*11efff7fSkettenis   return &current_ex_event;
1056*11efff7fSkettenis }
1057*11efff7fSkettenis 
1058*11efff7fSkettenis /* Signal frames.  */
1059*11efff7fSkettenis struct hppa_hpux_sigtramp_unwind_cache
1060*11efff7fSkettenis {
1061*11efff7fSkettenis   CORE_ADDR base;
1062*11efff7fSkettenis   struct trad_frame_saved_reg *saved_regs;
1063*11efff7fSkettenis };
1064*11efff7fSkettenis 
1065*11efff7fSkettenis static int hppa_hpux_tramp_reg[] = {
1066*11efff7fSkettenis   HPPA_SAR_REGNUM,
1067*11efff7fSkettenis   HPPA_PCOQ_HEAD_REGNUM,
1068*11efff7fSkettenis   HPPA_PCSQ_HEAD_REGNUM,
1069*11efff7fSkettenis   HPPA_PCOQ_TAIL_REGNUM,
1070*11efff7fSkettenis   HPPA_PCSQ_TAIL_REGNUM,
1071*11efff7fSkettenis   HPPA_EIEM_REGNUM,
1072*11efff7fSkettenis   HPPA_IIR_REGNUM,
1073*11efff7fSkettenis   HPPA_ISR_REGNUM,
1074*11efff7fSkettenis   HPPA_IOR_REGNUM,
1075*11efff7fSkettenis   HPPA_IPSW_REGNUM,
1076*11efff7fSkettenis   -1,
1077*11efff7fSkettenis   HPPA_SR4_REGNUM,
1078*11efff7fSkettenis   HPPA_SR4_REGNUM + 1,
1079*11efff7fSkettenis   HPPA_SR4_REGNUM + 2,
1080*11efff7fSkettenis   HPPA_SR4_REGNUM + 3,
1081*11efff7fSkettenis   HPPA_SR4_REGNUM + 4,
1082*11efff7fSkettenis   HPPA_SR4_REGNUM + 5,
1083*11efff7fSkettenis   HPPA_SR4_REGNUM + 6,
1084*11efff7fSkettenis   HPPA_SR4_REGNUM + 7,
1085*11efff7fSkettenis   HPPA_RCR_REGNUM,
1086*11efff7fSkettenis   HPPA_PID0_REGNUM,
1087*11efff7fSkettenis   HPPA_PID1_REGNUM,
1088*11efff7fSkettenis   HPPA_CCR_REGNUM,
1089*11efff7fSkettenis   HPPA_PID2_REGNUM,
1090*11efff7fSkettenis   HPPA_PID3_REGNUM,
1091*11efff7fSkettenis   HPPA_TR0_REGNUM,
1092*11efff7fSkettenis   HPPA_TR0_REGNUM + 1,
1093*11efff7fSkettenis   HPPA_TR0_REGNUM + 2,
1094*11efff7fSkettenis   HPPA_CR27_REGNUM
1095*11efff7fSkettenis };
1096*11efff7fSkettenis 
1097*11efff7fSkettenis static struct hppa_hpux_sigtramp_unwind_cache *
hppa_hpux_sigtramp_frame_unwind_cache(struct frame_info * next_frame,void ** this_cache)1098*11efff7fSkettenis hppa_hpux_sigtramp_frame_unwind_cache (struct frame_info *next_frame,
1099*11efff7fSkettenis 				       void **this_cache)
1100*11efff7fSkettenis 
1101*11efff7fSkettenis {
1102*11efff7fSkettenis   struct gdbarch *gdbarch = get_frame_arch (next_frame);
1103*11efff7fSkettenis   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
1104*11efff7fSkettenis   struct hppa_hpux_sigtramp_unwind_cache *info;
1105*11efff7fSkettenis   unsigned int flag;
1106*11efff7fSkettenis   CORE_ADDR sp, scptr;
1107*11efff7fSkettenis   int i, incr, off, szoff;
1108*11efff7fSkettenis 
1109*11efff7fSkettenis   if (*this_cache)
1110*11efff7fSkettenis     return *this_cache;
1111*11efff7fSkettenis 
1112*11efff7fSkettenis   info = FRAME_OBSTACK_ZALLOC (struct hppa_hpux_sigtramp_unwind_cache);
1113*11efff7fSkettenis   *this_cache = info;
1114*11efff7fSkettenis   info->saved_regs = trad_frame_alloc_saved_regs (next_frame);
1115*11efff7fSkettenis 
1116*11efff7fSkettenis   sp = frame_unwind_register_unsigned (next_frame, HPPA_SP_REGNUM);
1117*11efff7fSkettenis 
1118*11efff7fSkettenis   scptr = sp - 1352;
1119*11efff7fSkettenis   off = scptr;
1120*11efff7fSkettenis 
1121*11efff7fSkettenis   /* See /usr/include/machine/save_state.h for the structure of the save_state_t
1122*11efff7fSkettenis      structure. */
1123*11efff7fSkettenis 
1124*11efff7fSkettenis   flag = read_memory_unsigned_integer(scptr, 4);
1125*11efff7fSkettenis 
1126*11efff7fSkettenis   if (!(flag & 0x40))
1127*11efff7fSkettenis     {
1128*11efff7fSkettenis       /* Narrow registers. */
1129*11efff7fSkettenis       off = scptr + offsetof (save_state_t, ss_narrow);
1130*11efff7fSkettenis       incr = 4;
1131*11efff7fSkettenis       szoff = 0;
1132*11efff7fSkettenis     }
1133*11efff7fSkettenis   else
1134*11efff7fSkettenis     {
1135*11efff7fSkettenis       /* Wide registers. */
1136*11efff7fSkettenis       off = scptr + offsetof (save_state_t, ss_wide) + 8;
1137*11efff7fSkettenis       incr = 8;
1138*11efff7fSkettenis       szoff = (tdep->bytes_per_address == 4 ? 4 : 0);
1139*11efff7fSkettenis     }
1140*11efff7fSkettenis 
1141*11efff7fSkettenis   for (i = 1; i < 32; i++)
1142*11efff7fSkettenis     {
1143*11efff7fSkettenis       info->saved_regs[HPPA_R0_REGNUM + i].addr = off + szoff;
1144*11efff7fSkettenis       off += incr;
1145*11efff7fSkettenis     }
1146*11efff7fSkettenis 
1147*11efff7fSkettenis   for (i = 0;
1148*11efff7fSkettenis        i < sizeof(hppa_hpux_tramp_reg) / sizeof(hppa_hpux_tramp_reg[0]);
1149*11efff7fSkettenis        i++)
1150*11efff7fSkettenis     {
1151*11efff7fSkettenis       if (hppa_hpux_tramp_reg[i] > 0)
1152*11efff7fSkettenis         info->saved_regs[hppa_hpux_tramp_reg[i]].addr = off + szoff;
1153*11efff7fSkettenis       off += incr;
1154*11efff7fSkettenis     }
1155*11efff7fSkettenis 
1156*11efff7fSkettenis   /* TODO: fp regs */
1157*11efff7fSkettenis 
1158*11efff7fSkettenis   info->base = frame_unwind_register_unsigned (next_frame, HPPA_SP_REGNUM);
1159*11efff7fSkettenis 
1160*11efff7fSkettenis   return info;
1161*11efff7fSkettenis }
1162*11efff7fSkettenis 
1163*11efff7fSkettenis static void
hppa_hpux_sigtramp_frame_this_id(struct frame_info * next_frame,void ** this_prologue_cache,struct frame_id * this_id)1164*11efff7fSkettenis hppa_hpux_sigtramp_frame_this_id (struct frame_info *next_frame,
1165*11efff7fSkettenis 				   void **this_prologue_cache,
1166*11efff7fSkettenis 				   struct frame_id *this_id)
1167*11efff7fSkettenis {
1168*11efff7fSkettenis   struct hppa_hpux_sigtramp_unwind_cache *info
1169*11efff7fSkettenis     = hppa_hpux_sigtramp_frame_unwind_cache (next_frame, this_prologue_cache);
1170*11efff7fSkettenis   *this_id = frame_id_build (info->base, frame_pc_unwind (next_frame));
1171*11efff7fSkettenis }
1172*11efff7fSkettenis 
1173*11efff7fSkettenis static void
hppa_hpux_sigtramp_frame_prev_register(struct frame_info * next_frame,void ** this_prologue_cache,int regnum,int * optimizedp,enum lval_type * lvalp,CORE_ADDR * addrp,int * realnump,void * valuep)1174*11efff7fSkettenis hppa_hpux_sigtramp_frame_prev_register (struct frame_info *next_frame,
1175*11efff7fSkettenis 					 void **this_prologue_cache,
1176*11efff7fSkettenis 					 int regnum, int *optimizedp,
1177*11efff7fSkettenis 					 enum lval_type *lvalp,
1178*11efff7fSkettenis 					 CORE_ADDR *addrp,
1179*11efff7fSkettenis 					 int *realnump, void *valuep)
1180*11efff7fSkettenis {
1181*11efff7fSkettenis   struct hppa_hpux_sigtramp_unwind_cache *info
1182*11efff7fSkettenis     = hppa_hpux_sigtramp_frame_unwind_cache (next_frame, this_prologue_cache);
1183*11efff7fSkettenis   hppa_frame_prev_register_helper (next_frame, info->saved_regs, regnum,
1184*11efff7fSkettenis 		                   optimizedp, lvalp, addrp, realnump, valuep);
1185*11efff7fSkettenis }
1186*11efff7fSkettenis 
1187*11efff7fSkettenis static const struct frame_unwind hppa_hpux_sigtramp_frame_unwind = {
1188*11efff7fSkettenis   SIGTRAMP_FRAME,
1189*11efff7fSkettenis   hppa_hpux_sigtramp_frame_this_id,
1190*11efff7fSkettenis   hppa_hpux_sigtramp_frame_prev_register
1191*11efff7fSkettenis };
1192*11efff7fSkettenis 
1193*11efff7fSkettenis static const struct frame_unwind *
hppa_hpux_sigtramp_unwind_sniffer(struct frame_info * next_frame)1194*11efff7fSkettenis hppa_hpux_sigtramp_unwind_sniffer (struct frame_info *next_frame)
1195*11efff7fSkettenis {
1196*11efff7fSkettenis   CORE_ADDR pc = frame_pc_unwind (next_frame);
1197*11efff7fSkettenis   char *name;
1198*11efff7fSkettenis 
1199*11efff7fSkettenis   find_pc_partial_function (pc, &name, NULL, NULL);
1200*11efff7fSkettenis 
1201*11efff7fSkettenis   if (name && strcmp(name, "_sigreturn") == 0)
1202*11efff7fSkettenis     return &hppa_hpux_sigtramp_frame_unwind;
1203*11efff7fSkettenis 
1204*11efff7fSkettenis   return NULL;
1205*11efff7fSkettenis }
1206*11efff7fSkettenis 
1207*11efff7fSkettenis static CORE_ADDR
hppa_hpux_som_find_global_pointer(struct value * function)1208*11efff7fSkettenis hppa_hpux_som_find_global_pointer (struct value *function)
1209*11efff7fSkettenis {
1210*11efff7fSkettenis   CORE_ADDR faddr;
1211*11efff7fSkettenis 
1212*11efff7fSkettenis   faddr = value_as_address (function);
1213*11efff7fSkettenis 
1214*11efff7fSkettenis   /* Is this a plabel? If so, dereference it to get the gp value.  */
1215*11efff7fSkettenis   if (faddr & 2)
1216*11efff7fSkettenis     {
1217*11efff7fSkettenis       int status;
1218*11efff7fSkettenis       char buf[4];
1219*11efff7fSkettenis 
1220*11efff7fSkettenis       faddr &= ~3;
1221*11efff7fSkettenis 
1222*11efff7fSkettenis       status = target_read_memory (faddr + 4, buf, sizeof (buf));
1223*11efff7fSkettenis       if (status == 0)
1224*11efff7fSkettenis 	return extract_unsigned_integer (buf, sizeof (buf));
1225*11efff7fSkettenis     }
1226*11efff7fSkettenis 
1227*11efff7fSkettenis   return som_solib_get_got_by_pc (faddr);
1228*11efff7fSkettenis }
1229*11efff7fSkettenis 
1230*11efff7fSkettenis static CORE_ADDR
hppa_hpux_push_dummy_code(struct gdbarch * gdbarch,CORE_ADDR sp,CORE_ADDR funcaddr,int using_gcc,struct value ** args,int nargs,struct type * value_type,CORE_ADDR * real_pc,CORE_ADDR * bp_addr)1231*11efff7fSkettenis hppa_hpux_push_dummy_code (struct gdbarch *gdbarch, CORE_ADDR sp,
1232*11efff7fSkettenis 			   CORE_ADDR funcaddr, int using_gcc,
1233*11efff7fSkettenis 			   struct value **args, int nargs,
1234*11efff7fSkettenis 			   struct type *value_type,
1235*11efff7fSkettenis 			   CORE_ADDR *real_pc, CORE_ADDR *bp_addr)
1236*11efff7fSkettenis {
1237*11efff7fSkettenis   /* FIXME: tausq/2004-06-09: This needs much more testing.  It is broken
1238*11efff7fSkettenis      for pa64, but we should be able to get it to work with a little bit
1239*11efff7fSkettenis      of work. gdb-6.1 has a lot of code to handle various cases; I've tried to
1240*11efff7fSkettenis      simplify it and avoid compile-time conditionals.  */
1241*11efff7fSkettenis 
1242*11efff7fSkettenis   /* On HPUX, functions in the main executable and in libraries can be located
1243*11efff7fSkettenis      in different spaces.  In order for us to be able to select the right
1244*11efff7fSkettenis      space for the function call, we need to go through an instruction seqeunce
1245*11efff7fSkettenis      to select the right space for the target function, call it, and then
1246*11efff7fSkettenis      restore the space on return.
1247*11efff7fSkettenis 
1248*11efff7fSkettenis      There are two helper routines that can be used for this task -- if
1249*11efff7fSkettenis      an application is linked with gcc, it will contain a __gcc_plt_call
1250*11efff7fSkettenis      helper function.  __gcc_plt_call, when passed the entry point of an
1251*11efff7fSkettenis      import stub, will do the necessary space setting/restoration for the
1252*11efff7fSkettenis      target function.
1253*11efff7fSkettenis 
1254*11efff7fSkettenis      For programs that are compiled/linked with the HP compiler, a similar
1255*11efff7fSkettenis      function called __d_plt_call exists; __d_plt_call expects a PLABEL instead
1256*11efff7fSkettenis      of an import stub as an argument.
1257*11efff7fSkettenis 
1258*11efff7fSkettenis      // *INDENT-OFF*
1259*11efff7fSkettenis      To summarize, the call flow is:
1260*11efff7fSkettenis        current function -> dummy frame -> __gcc_plt_call (import stub)
1261*11efff7fSkettenis                         -> target function
1262*11efff7fSkettenis      or
1263*11efff7fSkettenis        current function -> dummy frame -> __d_plt_call (plabel)
1264*11efff7fSkettenis                         -> target function
1265*11efff7fSkettenis      // *INDENT-ON*
1266*11efff7fSkettenis 
1267*11efff7fSkettenis      In general the "funcaddr" argument passed to push_dummy_code is the actual
1268*11efff7fSkettenis      entry point of the target function.  For __gcc_plt_call, we need to
1269*11efff7fSkettenis      locate the import stub for the corresponding function.  Failing that,
1270*11efff7fSkettenis      we construct a dummy "import stub" on the stack to pass as an argument.
1271*11efff7fSkettenis      For __d_plt_call, we similarly synthesize a PLABEL on the stack to
1272*11efff7fSkettenis      pass to the helper function.
1273*11efff7fSkettenis 
1274*11efff7fSkettenis      An additional twist is that, in order for us to restore the space register
1275*11efff7fSkettenis      to its starting state, we need __gcc_plt_call/__d_plt_call to return
1276*11efff7fSkettenis      to the instruction where we started the call.  However, if we put
1277*11efff7fSkettenis      the breakpoint there, gdb will complain because it will find two
1278*11efff7fSkettenis      frames on the stack with the same (sp, pc) (with the dummy frame in
1279*11efff7fSkettenis      between).  Currently, we set the return pointer to (pc - 4) of the
1280*11efff7fSkettenis      current function.  FIXME: This is not an ideal solution; possibly if the
1281*11efff7fSkettenis      current pc is at the beginning of a page, this will cause a page fault.
1282*11efff7fSkettenis      Need to understand this better and figure out a better way to fix it.  */
1283*11efff7fSkettenis 
1284*11efff7fSkettenis   struct minimal_symbol *sym;
1285*11efff7fSkettenis 
1286*11efff7fSkettenis   /* Nonzero if we will use GCC's PLT call routine.  This routine must be
1287*11efff7fSkettenis      passed an import stub, not a PLABEL.  It is also necessary to get %r19
1288*11efff7fSkettenis      before performing the call.  (This is done by push_dummy_call.)  */
1289*11efff7fSkettenis   int use_gcc_plt_call = 1;
1290*11efff7fSkettenis 
1291*11efff7fSkettenis   /* See if __gcc_plt_call is available; if not we will use the HP version
1292*11efff7fSkettenis      instead.  */
1293*11efff7fSkettenis   sym = lookup_minimal_symbol ("__gcc_plt_call", NULL, NULL);
1294*11efff7fSkettenis   if (sym == NULL)
1295*11efff7fSkettenis     use_gcc_plt_call = 0;
1296*11efff7fSkettenis 
1297*11efff7fSkettenis   /* If using __gcc_plt_call, we need to make sure we pass in an import
1298*11efff7fSkettenis      stub.  funcaddr can be pointing to an export stub or a real function,
1299*11efff7fSkettenis      so we try to resolve it to the import stub.  */
1300*11efff7fSkettenis   if (use_gcc_plt_call)
1301*11efff7fSkettenis     {
1302*11efff7fSkettenis       struct objfile *objfile;
1303*11efff7fSkettenis       struct minimal_symbol *funsym, *stubsym;
1304*11efff7fSkettenis       CORE_ADDR stubaddr = 0;
1305*11efff7fSkettenis 
1306*11efff7fSkettenis       funsym = lookup_minimal_symbol_by_pc (funcaddr);
1307*11efff7fSkettenis       if (!funsym)
1308*11efff7fSkettenis         error ("Unable to find symbol for target function.\n");
1309*11efff7fSkettenis 
1310*11efff7fSkettenis       ALL_OBJFILES (objfile)
1311*11efff7fSkettenis         {
1312*11efff7fSkettenis 	  stubsym = lookup_minimal_symbol_solib_trampoline
1313*11efff7fSkettenis 	    (SYMBOL_LINKAGE_NAME (funsym), objfile);
1314*11efff7fSkettenis 
1315*11efff7fSkettenis           if (stubsym)
1316*11efff7fSkettenis 	    {
1317*11efff7fSkettenis 	      struct unwind_table_entry *u;
1318*11efff7fSkettenis 
1319*11efff7fSkettenis 	      u = find_unwind_entry (SYMBOL_VALUE (stubsym));
1320*11efff7fSkettenis 	      if (u == NULL
1321*11efff7fSkettenis 	          || (u->stub_unwind.stub_type != IMPORT
1322*11efff7fSkettenis 		      && u->stub_unwind.stub_type != IMPORT_SHLIB))
1323*11efff7fSkettenis 	        continue;
1324*11efff7fSkettenis 
1325*11efff7fSkettenis               stubaddr = SYMBOL_VALUE (stubsym);
1326*11efff7fSkettenis 
1327*11efff7fSkettenis 	      /* If we found an IMPORT stub, then we can stop searching;
1328*11efff7fSkettenis 	         if we found an IMPORT_SHLIB, we want to continue the search
1329*11efff7fSkettenis 		 in the hopes that we will find an IMPORT stub.  */
1330*11efff7fSkettenis 	      if (u->stub_unwind.stub_type == IMPORT)
1331*11efff7fSkettenis 	        break;
1332*11efff7fSkettenis 	    }
1333*11efff7fSkettenis 	}
1334*11efff7fSkettenis 
1335*11efff7fSkettenis       if (stubaddr != 0)
1336*11efff7fSkettenis         {
1337*11efff7fSkettenis           /* Argument to __gcc_plt_call is passed in r22.  */
1338*11efff7fSkettenis           regcache_cooked_write_unsigned (current_regcache, 22, stubaddr);
1339*11efff7fSkettenis         }
1340*11efff7fSkettenis       else
1341*11efff7fSkettenis         {
1342*11efff7fSkettenis 	  /* No import stub found; let's synthesize one.  */
1343*11efff7fSkettenis 
1344*11efff7fSkettenis 	  /* ldsid %r21, %r1 */
1345*11efff7fSkettenis 	  write_memory_unsigned_integer (sp, 4, 0x02a010a1);
1346*11efff7fSkettenis 	  /* mtsp %r1,%sr0 */
1347*11efff7fSkettenis 	  write_memory_unsigned_integer (sp + 4, 4, 0x00011820);
1348*11efff7fSkettenis 	  /* be 0(%sr0, %r21) */
1349*11efff7fSkettenis 	  write_memory_unsigned_integer (sp + 8, 4, 0xe2a00000);
1350*11efff7fSkettenis           /* nop */
1351*11efff7fSkettenis           write_memory_unsigned_integer (sp + 12, 4, 0x08000240);
1352*11efff7fSkettenis 
1353*11efff7fSkettenis           regcache_cooked_write_unsigned (current_regcache, 21, funcaddr);
1354*11efff7fSkettenis           regcache_cooked_write_unsigned (current_regcache, 22, sp);
1355*11efff7fSkettenis 	}
1356*11efff7fSkettenis 
1357*11efff7fSkettenis       /* We set the breakpoint address and r31 to (close to) where the current
1358*11efff7fSkettenis          pc is; when __gcc_plt_call returns, it will restore pcsqh to the
1359*11efff7fSkettenis 	 current value based on this.  The -4 is needed for frame unwinding
1360*11efff7fSkettenis 	 to work properly -- we need to land in a different function than
1361*11efff7fSkettenis 	 the current function.  */
1362*11efff7fSkettenis       *bp_addr = (read_register (HPPA_PCOQ_HEAD_REGNUM) & ~3) - 4;
1363*11efff7fSkettenis       regcache_cooked_write_unsigned (current_regcache, 31, *bp_addr);
1364*11efff7fSkettenis 
1365*11efff7fSkettenis       /* Continue from __gcc_plt_call.  */
1366*11efff7fSkettenis       *real_pc = SYMBOL_VALUE (sym);
1367*11efff7fSkettenis     }
1368*11efff7fSkettenis   else
1369*11efff7fSkettenis     {
1370*11efff7fSkettenis       unsigned int gp;
1371*11efff7fSkettenis 
1372*11efff7fSkettenis       /* Use __d_plt_call as a fallback; __d_plt_call expects to be called
1373*11efff7fSkettenis          with a plabel, so we need to build one.  */
1374*11efff7fSkettenis 
1375*11efff7fSkettenis       sym = lookup_minimal_symbol ("__d_plt_call", NULL, NULL);
1376*11efff7fSkettenis       if (sym == NULL)
1377*11efff7fSkettenis         error("Can't find an address for __d_plt_call or __gcc_plt_call "
1378*11efff7fSkettenis 	      "trampoline\nSuggest linking executable with -g or compiling "
1379*11efff7fSkettenis 	      "with gcc.");
1380*11efff7fSkettenis 
1381*11efff7fSkettenis       gp = gdbarch_tdep (gdbarch)->find_global_pointer (funcaddr);
1382*11efff7fSkettenis       write_memory_unsigned_integer (sp, 4, funcaddr);
1383*11efff7fSkettenis       write_memory_unsigned_integer (sp + 4, 4, gp);
1384*11efff7fSkettenis 
1385*11efff7fSkettenis       /* plabel is passed in r22 */
1386*11efff7fSkettenis       regcache_cooked_write_unsigned (current_regcache, 22, sp);
1387*11efff7fSkettenis     }
1388*11efff7fSkettenis 
1389*11efff7fSkettenis   /* Pushed one stack frame, which has to be 64-byte aligned.  */
1390*11efff7fSkettenis   sp += 64;
1391*11efff7fSkettenis 
1392*11efff7fSkettenis   return sp;
1393*11efff7fSkettenis }
1394*11efff7fSkettenis 
1395*11efff7fSkettenis static void
hppa_hpux_inferior_created(struct target_ops * objfile,int from_tty)1396*11efff7fSkettenis hppa_hpux_inferior_created (struct target_ops *objfile, int from_tty)
1397*11efff7fSkettenis {
1398*11efff7fSkettenis   /* Some HP-UX related globals to clear when a new "main"
1399*11efff7fSkettenis      symbol file is loaded.  HP-specific.  */
1400*11efff7fSkettenis   deprecated_hp_som_som_object_present = 0;
1401*11efff7fSkettenis   hp_cxx_exception_support_initialized = 0;
1402b725ae77Skettenis }
1403b725ae77Skettenis 
1404b725ae77Skettenis static void
hppa_hpux_init_abi(struct gdbarch_info info,struct gdbarch * gdbarch)1405b725ae77Skettenis hppa_hpux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
1406b725ae77Skettenis {
1407*11efff7fSkettenis   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
1408*11efff7fSkettenis 
1409*11efff7fSkettenis   if (tdep->bytes_per_address == 4)
1410*11efff7fSkettenis     set_gdbarch_in_solib_call_trampoline (gdbarch,
1411*11efff7fSkettenis 					  hppa32_hpux_in_solib_call_trampoline);
1412*11efff7fSkettenis   else
1413*11efff7fSkettenis     set_gdbarch_in_solib_call_trampoline (gdbarch,
1414*11efff7fSkettenis 					  hppa64_hpux_in_solib_call_trampoline);
1415*11efff7fSkettenis 
1416*11efff7fSkettenis   set_gdbarch_in_solib_return_trampoline (gdbarch,
1417*11efff7fSkettenis 					  hppa_hpux_in_solib_return_trampoline);
1418*11efff7fSkettenis   set_gdbarch_skip_trampoline_code (gdbarch, hppa_hpux_skip_trampoline_code);
1419*11efff7fSkettenis 
1420*11efff7fSkettenis   set_gdbarch_push_dummy_code (gdbarch, hppa_hpux_push_dummy_code);
1421*11efff7fSkettenis   set_gdbarch_call_dummy_location (gdbarch, ON_STACK);
1422*11efff7fSkettenis 
1423*11efff7fSkettenis   frame_unwind_append_sniffer (gdbarch, hppa_hpux_sigtramp_unwind_sniffer);
1424*11efff7fSkettenis 
1425*11efff7fSkettenis   observer_attach_inferior_created (hppa_hpux_inferior_created);
1426b725ae77Skettenis }
1427b725ae77Skettenis 
1428b725ae77Skettenis static void
hppa_hpux_som_init_abi(struct gdbarch_info info,struct gdbarch * gdbarch)1429b725ae77Skettenis hppa_hpux_som_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
1430b725ae77Skettenis {
1431*11efff7fSkettenis   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
1432*11efff7fSkettenis 
1433*11efff7fSkettenis   tdep->is_elf = 0;
1434*11efff7fSkettenis 
1435*11efff7fSkettenis   tdep->find_global_pointer = hppa_hpux_som_find_global_pointer;
1436b725ae77Skettenis   hppa_hpux_init_abi (info, gdbarch);
1437b725ae77Skettenis }
1438b725ae77Skettenis 
1439b725ae77Skettenis static void
hppa_hpux_elf_init_abi(struct gdbarch_info info,struct gdbarch * gdbarch)1440b725ae77Skettenis hppa_hpux_elf_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
1441b725ae77Skettenis {
1442*11efff7fSkettenis   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
1443*11efff7fSkettenis 
1444*11efff7fSkettenis   tdep->is_elf = 1;
1445b725ae77Skettenis   hppa_hpux_init_abi (info, gdbarch);
1446b725ae77Skettenis }
1447b725ae77Skettenis 
1448b725ae77Skettenis void
_initialize_hppa_hpux_tdep(void)1449b725ae77Skettenis _initialize_hppa_hpux_tdep (void)
1450b725ae77Skettenis {
1451b725ae77Skettenis   gdbarch_register_osabi (bfd_arch_hppa, 0, GDB_OSABI_HPUX_SOM,
1452b725ae77Skettenis                           hppa_hpux_som_init_abi);
1453b725ae77Skettenis   gdbarch_register_osabi (bfd_arch_hppa, bfd_mach_hppa20w, GDB_OSABI_HPUX_ELF,
1454b725ae77Skettenis                           hppa_hpux_elf_init_abi);
1455b725ae77Skettenis }
1456