implement support for "enum class"
[platform/upstream/binutils.git] / gdb / solib-ia64-hpux.c
1 /* Copyright (C) 2010-2014 Free Software Foundation, Inc.
2
3    This file is part of GDB.
4
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 3 of the License, or
8    (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
17
18 #include "defs.h"
19 #include "ia64-tdep.h"
20 #include "ia64-hpux-tdep.h"
21 #include "solib-ia64-hpux.h"
22 #include "solist.h"
23 #include "solib.h"
24 #include "target.h"
25 #include "gdbtypes.h"
26 #include "inferior.h"
27 #include "gdbcore.h"
28 #include "regcache.h"
29 #include "opcode/ia64.h"
30 #include "symfile.h"
31 #include "objfiles.h"
32 #include "elf-bfd.h"
33 #include "exceptions.h"
34
35 /* Need to define the following macro in order to get the complete
36    load_module_desc struct definition in dlfcn.h  Otherwise, it doesn't
37    match the size of the struct the loader is providing us during load
38    events.  */
39 #define _LOAD_MODULE_DESC_EXT
40
41 #include <sys/ttrace.h>
42 #include <dlfcn.h>
43 #include <elf.h>
44 #include <service_mgr.h>
45
46 /* The following is to have access to the definition of type load_info_t.  */
47 #include <crt0.h>
48
49 /* The r32 pseudo-register number.
50
51    Like all stacked registers, r32 is treated as a pseudo-register,
52    because it is not always available for read/write via the ttrace
53    interface.  */
54 /* This is a bit of a hack, as we duplicate something hidden inside
55    ia64-tdep.c, but oh well...  */
56 #define IA64_R32_PSEUDO_REGNUM (IA64_NAT127_REGNUM + 2)
57
58 /* Our struct so_list private data structure.  */
59
60 struct lm_info
61 {
62   /* The shared library module descriptor.  We extract this structure
63      from the loader at the time the shared library gets mapped.  */
64   struct load_module_desc module_desc;
65
66   /* The text segment address as defined in the shared library object
67      (this is not the address where this segment got loaded).  This
68      field is initially set to zero, and computed lazily.  */
69   CORE_ADDR text_start;
70
71   /* The data segment address as defined in the shared library object
72      (this is not the address where this segment got loaded).  This
73      field is initially set to zero, and computed lazily.  */
74   CORE_ADDR data_start;
75 };
76
77 /* The list of shared libraries currently mapped by the inferior.  */
78
79 static struct so_list *so_list_head = NULL;
80
81 /* Create a new so_list element.  The result should be deallocated
82    when no longer in use.  */
83
84 static struct so_list *
85 new_so_list (char *so_name, struct load_module_desc module_desc)
86 {
87   struct so_list *new_so;
88
89   new_so = (struct so_list *) XCNEW (struct so_list);
90   new_so->lm_info = (struct lm_info *) XCNEW (struct lm_info);
91   new_so->lm_info->module_desc = module_desc;
92
93   strncpy (new_so->so_name, so_name, SO_NAME_MAX_PATH_SIZE - 1);
94   new_so->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0';
95   strcpy (new_so->so_original_name, new_so->so_name);
96
97   return new_so;
98 }
99
100 /* Return non-zero if the instruction at the current PC is a breakpoint
101    part of the dynamic loading process.
102
103    We identify such instructions by checking that the instruction at
104    the current pc is a break insn where no software breakpoint has been
105    inserted by us.  We also verify that the operands have specific
106    known values, to be extra certain.
107
108    PTID is the ptid of the thread that should be checked, but this
109    function also assumes that inferior_ptid is already equal to PTID.
110    Ideally, we would like to avoid the requirement on inferior_ptid,
111    but many routines still use the inferior_ptid global to access
112    the relevant thread's register and memory.  We still have the ptid
113    as parameter to be able to pass it to the routines that do take a ptid
114    - that way we avoid increasing explicit uses of the inferior_ptid
115    global.  */
116
117 static int
118 ia64_hpux_at_dld_breakpoint_1_p (ptid_t ptid)
119 {
120   struct regcache *regcache = get_thread_regcache (ptid);
121   CORE_ADDR pc = regcache_read_pc (regcache);
122   struct address_space *aspace = get_regcache_aspace (regcache);
123   ia64_insn t0, t1, slot[3], template, insn;
124   int slotnum;
125   bfd_byte bundle[16];
126
127   /* If this is a regular breakpoint, then it can not be a dld one.  */
128   if (breakpoint_inserted_here_p (aspace, pc))
129     return 0;
130
131   slotnum = ((long) pc) & 0xf;
132   if (slotnum > 2)
133     internal_error (__FILE__, __LINE__,
134                     "invalid slot (%d) for address %s", slotnum,
135                     paddress (get_regcache_arch (regcache), pc));
136
137   pc -= (pc & 0xf);
138   read_memory (pc, bundle, sizeof (bundle));
139
140   /* bundles are always in little-endian byte order */
141   t0 = bfd_getl64 (bundle);
142   t1 = bfd_getl64 (bundle + 8);
143   template = (t0 >> 1) & 0xf;
144   slot[0] = (t0 >>  5) & 0x1ffffffffffLL;
145   slot[1] = ((t0 >> 46) & 0x3ffff) | ((t1 & 0x7fffff) << 18);
146   slot[2] = (t1 >> 23) & 0x1ffffffffffLL;
147
148   if (template == 2 && slotnum == 1)
149     {
150       /* skip L slot in MLI template: */
151       slotnum = 2;
152     }
153
154   insn = slot[slotnum];
155
156   return (insn == 0x1c0c9c0       /* break.i 0x070327 */
157           || insn == 0x3c0c9c0);  /* break.i 0x0f0327 */
158 }
159
160 /* Same as ia64_hpux_at_dld_breakpoint_1_p above, with the following
161    differences: It temporarily sets inferior_ptid to PTID, and also
162    contains any exception being raised.  */
163
164 int
165 ia64_hpux_at_dld_breakpoint_p (ptid_t ptid)
166 {
167   volatile struct gdb_exception e;
168   ptid_t saved_ptid = inferior_ptid;
169   int result = 0;
170
171   inferior_ptid = ptid;
172   TRY_CATCH (e, RETURN_MASK_ALL)
173     {
174       result = ia64_hpux_at_dld_breakpoint_1_p (ptid);
175     }
176   inferior_ptid = saved_ptid;
177   if (e.reason < 0)
178     warning (_("error while checking for dld breakpoint: %s"), e.message);
179
180   return result;
181 }
182
183 /* Handler for library load event: Read the information provided by
184    the loader, and then use it to read the shared library symbols.  */
185
186 static void
187 ia64_hpux_handle_load_event (struct regcache *regcache)
188 {
189   CORE_ADDR module_desc_addr;
190   ULONGEST module_desc_size;
191   CORE_ADDR so_path_addr;
192   char so_path[PATH_MAX];
193   struct load_module_desc module_desc;
194   struct so_list *new_so;
195
196   /* Extract the data provided by the loader as follow:
197        - r33: Address of load_module_desc structure
198        - r34: size of struct load_module_desc
199        - r35: Address of string holding shared library path
200    */
201   regcache_cooked_read_unsigned (regcache, IA64_R32_PSEUDO_REGNUM + 1,
202                                  &module_desc_addr);
203   regcache_cooked_read_unsigned (regcache, IA64_R32_PSEUDO_REGNUM + 2,
204                                  &module_desc_size);
205   regcache_cooked_read_unsigned (regcache, IA64_R32_PSEUDO_REGNUM + 3,
206                                  &so_path_addr);
207
208   if (module_desc_size != sizeof (struct load_module_desc))
209     warning (_("load_module_desc size (%ld) != size returned by kernel (%s)"),
210              sizeof (struct load_module_desc),
211              pulongest (module_desc_size));
212
213   read_memory_string (so_path_addr, so_path, PATH_MAX);
214   read_memory (module_desc_addr, (gdb_byte *) &module_desc,
215                sizeof (module_desc));
216
217   /* Create a new so_list element and insert it at the start of our
218      so_list_head (we insert at the start of the list only because
219      it is less work compared to inserting it elsewhere).  */
220   new_so = new_so_list (so_path, module_desc);
221   new_so->next = so_list_head;
222   so_list_head = new_so;
223 }
224
225 /* Update the value of the PC to point to the begining of the next
226    instruction bundle.  */
227
228 static void
229 ia64_hpux_move_pc_to_next_bundle (struct regcache *regcache)
230 {
231   CORE_ADDR pc = regcache_read_pc (regcache);
232
233   pc -= pc & 0xf;
234   pc += 16;
235   ia64_write_pc (regcache, pc);
236 }
237
238 /* Handle loader events.
239
240    PTID is the ptid of the thread corresponding to the event being
241    handled.  Similarly to ia64_hpux_at_dld_breakpoint_1_p, this
242    function assumes that inferior_ptid is set to PTID.  */
243
244 static void
245 ia64_hpux_handle_dld_breakpoint_1 (ptid_t ptid)
246 {
247   struct regcache *regcache = get_thread_regcache (ptid);
248   ULONGEST arg0;
249
250   /* The type of event is provided by the loaded via r32.  */
251   regcache_cooked_read_unsigned (regcache, IA64_R32_PSEUDO_REGNUM, &arg0);
252   switch (arg0)
253     {
254       case BREAK_DE_SVC_LOADED:
255         /* Currently, the only service loads are uld and dld,
256            so we shouldn't need to do anything.  Just ignore.  */
257         break;
258       case BREAK_DE_LIB_LOADED:
259         ia64_hpux_handle_load_event (regcache);
260         solib_add (NULL, 0, &current_target, auto_solib_add);
261         break;
262       case BREAK_DE_LIB_UNLOADED:
263       case BREAK_DE_LOAD_COMPLETE:
264       case BREAK_DE_BOR:
265         /* Ignore for now.  */
266         break;
267     }
268
269   /* Now that we have handled the event, we can move the PC to
270      the next instruction bundle, past the break instruction.  */
271   ia64_hpux_move_pc_to_next_bundle (regcache);
272 }
273
274 /* Same as ia64_hpux_handle_dld_breakpoint_1 above, with the following
275    differences: This function temporarily sets inferior_ptid to PTID,
276    and also contains any exception.  */
277
278 void
279 ia64_hpux_handle_dld_breakpoint (ptid_t ptid)
280 {
281   volatile struct gdb_exception e;
282   ptid_t saved_ptid = inferior_ptid;
283
284   inferior_ptid = ptid;
285   TRY_CATCH (e, RETURN_MASK_ALL)
286     {
287       ia64_hpux_handle_dld_breakpoint_1 (ptid);
288     }
289   inferior_ptid = saved_ptid;
290   if (e.reason < 0)
291     warning (_("error detected while handling dld breakpoint: %s"), e.message);
292 }
293
294 /* Find the address of the code and data segments in ABFD, and update
295    TEXT_START and DATA_START accordingly.  */
296
297 static void
298 ia64_hpux_find_start_vma (bfd *abfd, CORE_ADDR *text_start,
299                           CORE_ADDR *data_start)
300 {
301   Elf_Internal_Ehdr *i_ehdrp = elf_elfheader (abfd);
302   Elf64_Phdr phdr;
303   int i;
304
305   *text_start = 0;
306   *data_start = 0;
307
308   if (bfd_seek (abfd, i_ehdrp->e_phoff, SEEK_SET) == -1)
309     error (_("invalid program header offset in %s"), abfd->filename);
310
311   for (i = 0; i < i_ehdrp->e_phnum; i++)
312     {
313       if (bfd_bread (&phdr, sizeof (phdr), abfd) != sizeof (phdr))
314         error (_("failed to read segment %d in %s"), i, abfd->filename);
315
316       if (phdr.p_flags & PF_X
317           && (*text_start == 0 || phdr.p_vaddr < *text_start))
318         *text_start = phdr.p_vaddr;
319
320       if (phdr.p_flags & PF_W
321           && (*data_start == 0 || phdr.p_vaddr < *data_start))
322         *data_start = phdr.p_vaddr;
323     }
324 }
325
326 /* The "relocate_section_addresses" target_so_ops routine for ia64-hpux.  */
327
328 static void
329 ia64_hpux_relocate_section_addresses (struct so_list *so,
330                                       struct target_section *sec)
331 {
332   CORE_ADDR offset = 0;
333
334   /* If we haven't computed the text & data segment addresses, do so now.
335      We do this here, because we now have direct access to the associated
336      bfd, whereas we would have had to open our own if we wanted to do it
337      while processing the library-load event.  */
338   if (so->lm_info->text_start == 0 && so->lm_info->data_start == 0)
339     ia64_hpux_find_start_vma (sec->the_bfd_section->owner,
340                               &so->lm_info->text_start,
341                               &so->lm_info->data_start);
342
343   /* Determine the relocation offset based on which segment
344      the section belongs to.  */
345   if ((so->lm_info->text_start < so->lm_info->data_start
346        && sec->addr < so->lm_info->data_start)
347       || (so->lm_info->text_start > so->lm_info->data_start
348           && sec->addr >= so->lm_info->text_start))
349     offset = so->lm_info->module_desc.text_base - so->lm_info->text_start;
350   else if ((so->lm_info->text_start < so->lm_info->data_start
351             && sec->addr >= so->lm_info->data_start)
352            || (so->lm_info->text_start > so->lm_info->data_start
353                && sec->addr < so->lm_info->text_start))
354     offset = so->lm_info->module_desc.data_base - so->lm_info->data_start;
355
356   /* And now apply the relocation.  */
357   sec->addr += offset;
358   sec->endaddr += offset;
359
360   /* Best effort to set addr_high/addr_low.  This is used only by
361      'info sharedlibrary'.  */
362   if (so->addr_low == 0 || sec->addr < so->addr_low)
363     so->addr_low = sec->addr;
364
365   if (so->addr_high == 0 || sec->endaddr > so->addr_high)
366     so->addr_high = sec->endaddr;
367 }
368
369 /* The "free_so" target_so_ops routine for ia64-hpux.  */
370
371 static void
372 ia64_hpux_free_so (struct so_list *so)
373 {
374   xfree (so->lm_info);
375 }
376
377 /* The "clear_solib" target_so_ops routine for ia64-hpux.  */
378
379 static void
380 ia64_hpux_clear_solib (void)
381 {
382   struct so_list *so;
383
384   while (so_list_head != NULL)
385     {
386       so = so_list_head;
387       so_list_head = so_list_head->next;
388
389       ia64_hpux_free_so (so);
390       xfree (so);
391     }
392 }
393
394 /* Assuming the inferior just stopped on an EXEC event, return
395    the address of the load_info_t structure.  */
396
397 static CORE_ADDR
398 ia64_hpux_get_load_info_addr (void)
399 {
400   struct type *data_ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr;
401   CORE_ADDR addr;
402   int status;
403
404   /* The address of the load_info_t structure is stored in the 4th
405      argument passed to the initial thread of the process (in other
406      words, in argv[3]).  So get the address of these arguments,
407      and extract the 4th one.  */
408   status = ttrace (TT_PROC_GET_ARGS, ptid_get_pid (inferior_ptid),
409                    0, (uintptr_t) &addr, sizeof (CORE_ADDR), 0);
410   if (status == -1 && errno)
411     perror_with_name (_("Unable to get argument list"));
412   return (read_memory_typed_address (addr + 3 * 8, data_ptr_type));
413 }
414
415 /* A structure used to aggregate some information extracted from
416    the dynamic section of the main executable.  */
417
418 struct dld_info
419 {
420   ULONGEST dld_flags;
421   CORE_ADDR load_map;
422 };
423
424 /* Scan the ".dynamic" section referenced by ABFD and DYN_SECT,
425    and extract the information needed to fill in INFO.  */
426
427 static void
428 ia64_hpux_read_dynamic_info (struct gdbarch *gdbarch, bfd *abfd,
429                              asection *dyn_sect, struct dld_info *info)
430 {
431   int sect_size;
432   char *buf;
433   char *buf_end;
434
435   /* Make sure that info always has initialized data, even if we fail
436      to read the syn_sect section.  */
437   memset (info, 0, sizeof (struct dld_info));
438
439   sect_size = bfd_section_size (abfd, dyn_sect);
440   buf = alloca (sect_size);
441   buf_end = buf + sect_size;
442
443   if (bfd_seek (abfd, dyn_sect->filepos, SEEK_SET) != 0
444       || bfd_bread (buf, sect_size, abfd) != sect_size)
445     error (_("failed to read contents of .dynamic section"));
446
447   for (; buf < buf_end; buf += sizeof (Elf64_Dyn))
448     {
449       Elf64_Dyn *dynp = (Elf64_Dyn *) buf;
450       Elf64_Sxword d_tag;
451
452       d_tag = bfd_h_get_64 (abfd, &dynp->d_tag);
453       switch (d_tag)
454         {
455           case DT_HP_DLD_FLAGS:
456             info->dld_flags = bfd_h_get_64 (abfd, &dynp->d_un);
457             break;
458
459           case DT_HP_LOAD_MAP:
460             {
461               CORE_ADDR load_map_addr = bfd_h_get_64 (abfd, &dynp->d_un.d_ptr);
462
463               if (target_read_memory (load_map_addr,
464                                       (gdb_byte *) &info->load_map,
465                                       sizeof (info->load_map)) != 0)
466                 error (_("failed to read load map at %s"),
467                        paddress (gdbarch, load_map_addr));
468             }
469             break;
470         }
471     }
472 }
473
474 /* Wrapper around target_read_memory used with libdl.  */
475
476 static void *
477 ia64_hpux_read_tgt_mem (void *buffer, uint64_t ptr, size_t bufsiz, int ident)
478 {
479   if (target_read_memory (ptr, (gdb_byte *) buffer, bufsiz) != 0)
480     return 0;
481   else
482     return buffer;
483 }
484
485 /* Create a new so_list object for a shared library, and store that
486    new so_list object in our SO_LIST_HEAD list.
487
488    SO_INDEX is an index specifying the placement of the loaded shared
489    library in the dynamic loader's search list.  Normally, this index
490    is strictly positive, but an index of -1 refers to the loader itself.
491
492    Return nonzero if the so_list object could be created.  A null
493    return value with a positive SO_INDEX normally means that there are
494    no more entries in the dynamic loader's search list at SO_INDEX or
495    beyond.  */
496
497 static int
498 ia64_hpux_add_so_from_dld_info (struct dld_info info, int so_index)
499 {
500   struct load_module_desc module_desc;
501   uint64_t so_handle;
502   char *so_path;
503   struct so_list *so;
504
505   so_handle = dlgetmodinfo (so_index, &module_desc, sizeof (module_desc),
506                             ia64_hpux_read_tgt_mem, 0, info.load_map);
507
508   if (so_handle == 0)
509     /* No such entry.  We probably reached the end of the list.  */
510     return 0;
511
512   so_path = dlgetname (&module_desc, sizeof (module_desc),
513                        ia64_hpux_read_tgt_mem, 0, info.load_map);
514   if (so_path == NULL)
515     {
516       /* Should never happen, but let's not crash if it does.  */
517       warning (_("unable to get shared library name, symbols not loaded"));
518       return 0;
519     }
520
521   /* Create a new so_list and insert it at the start of our list.
522      The order is not extremely important, but it's less work to do so
523      at the end of the list.  */
524   so = new_so_list (so_path, module_desc);
525   so->next = so_list_head;
526   so_list_head = so;
527
528   return 1;
529 }
530
531 /* Assuming we just attached to a process, update our list of shared
532    libraries (SO_LIST_HEAD) as well as GDB's list.  */
533
534 static void
535 ia64_hpux_solib_add_after_attach (void)
536 {
537   bfd *abfd;
538   asection *dyn_sect;
539   struct dld_info info;
540   int i;
541
542   if (symfile_objfile == NULL)
543     return;
544
545   abfd = symfile_objfile->obfd;
546   dyn_sect = bfd_get_section_by_name (abfd, ".dynamic");
547
548   if (dyn_sect == NULL || bfd_section_size (abfd, dyn_sect) == 0)
549     return;
550
551   ia64_hpux_read_dynamic_info (get_objfile_arch (symfile_objfile), abfd,
552                                dyn_sect, &info);
553
554   if ((info.dld_flags & DT_HP_DEBUG_PRIVATE) == 0)
555     {
556       warning (_(
557 "The shared libraries were not privately mapped; setting a breakpoint\n\
558 in a shared library will not work until you rerun the program.\n\
559 Use the following command to enable debugging of shared libraries.\n\
560 chatr +dbg enable a.out"));
561     }
562
563   /* Read the symbols of the dynamic loader (dld.so).  */
564   ia64_hpux_add_so_from_dld_info (info, -1);
565
566   /* Read the symbols of all the other shared libraries.  */
567   for (i = 1; ; i++)
568     if (!ia64_hpux_add_so_from_dld_info (info, i))
569       break;  /* End of list.  */
570
571   /* Resync the library list at the core level.  */
572   solib_add (NULL, 1, &current_target, auto_solib_add);
573 }
574
575 /* The "create_inferior_hook" target_so_ops routine for ia64-hpux.  */
576
577 static void
578 ia64_hpux_solib_create_inferior_hook (int from_tty)
579 {
580   CORE_ADDR load_info_addr;
581   load_info_t load_info;
582
583   /* Initially, we were thinking about adding a check that the program
584      (accessible through symfile_objfile) was linked against some shared
585      libraries, by searching for a ".dynamic" section.  However, could
586      this break in the case of a statically linked program that later
587      uses dlopen?  Programs that are fully statically linked are very
588      rare, and we will worry about them when we encounter one that
589      causes trouble.  */
590
591   /* Set the LI_TRACE flag in the load_info_t structure.  This enables
592      notifications when shared libraries are being mapped.  */
593   load_info_addr = ia64_hpux_get_load_info_addr ();
594   read_memory (load_info_addr, (gdb_byte *) &load_info, sizeof (load_info));
595   load_info.li_flags |= LI_TRACE;
596   write_memory (load_info_addr, (gdb_byte *) &load_info, sizeof (load_info));
597
598   /* If we just attached to our process, some shard libraries have
599      already been mapped.  Find which ones they are...  */
600   if (current_inferior ()->attach_flag)
601     ia64_hpux_solib_add_after_attach ();
602 }
603
604 /* The "special_symbol_handling" target_so_ops routine for ia64-hpux.  */
605
606 static void
607 ia64_hpux_special_symbol_handling (void)
608 {
609   /* Nothing to do.  */
610 }
611
612 /* The "current_sos" target_so_ops routine for ia64-hpux.  */
613
614 static struct so_list *
615 ia64_hpux_current_sos (void)
616 {
617   /* Return a deep copy of our own list.  */
618   struct so_list *new_head = NULL, *prev_new_so = NULL;
619   struct so_list *our_so;
620
621   for (our_so = so_list_head; our_so != NULL; our_so = our_so->next)
622     {
623       struct so_list *new_so;
624
625       new_so = new_so_list (our_so->so_name, our_so->lm_info->module_desc);
626       if (prev_new_so != NULL)
627         prev_new_so->next = new_so;
628       prev_new_so = new_so;
629       if (new_head == NULL)
630         new_head = new_so;
631     }
632
633   return new_head;
634 }
635
636 /* The "open_symbol_file_object" target_so_ops routine for ia64-hpux.  */
637
638 static int
639 ia64_hpux_open_symbol_file_object (void *from_ttyp)
640 {
641   return 0;
642 }
643
644 /* The "in_dynsym_resolve_code" target_so_ops routine for ia64-hpux.  */
645
646 static int
647 ia64_hpux_in_dynsym_resolve_code (CORE_ADDR pc)
648 {
649   return 0;
650 }
651
652 /* If FADDR is the address of a function inside one of the shared
653    libraries, return the shared library linkage address.  */
654
655 CORE_ADDR
656 ia64_hpux_get_solib_linkage_addr (CORE_ADDR faddr)
657 {
658   struct so_list *so = so_list_head;
659
660   while (so != NULL)
661     {
662       struct load_module_desc module_desc = so->lm_info->module_desc;
663
664       if (module_desc.text_base <= faddr
665           && (module_desc.text_base + module_desc.text_size) > faddr)
666         return module_desc.linkage_ptr;
667
668       so = so->next;
669     }
670
671   return 0;
672 }
673
674 /* Create a new target_so_ops structure suitable for ia64-hpux, and
675    return its address.  */
676
677 static struct target_so_ops *
678 ia64_hpux_target_so_ops (void)
679 {
680   struct target_so_ops *ops = XCNEW (struct target_so_ops);
681
682   ops->relocate_section_addresses = ia64_hpux_relocate_section_addresses;
683   ops->free_so = ia64_hpux_free_so;
684   ops->clear_solib = ia64_hpux_clear_solib;
685   ops->solib_create_inferior_hook = ia64_hpux_solib_create_inferior_hook;
686   ops->special_symbol_handling = ia64_hpux_special_symbol_handling;
687   ops->current_sos = ia64_hpux_current_sos;
688   ops->open_symbol_file_object = ia64_hpux_open_symbol_file_object;
689   ops->in_dynsym_resolve_code = ia64_hpux_in_dynsym_resolve_code;
690   ops->bfd_open = solib_bfd_open;
691
692   return ops;
693 }
694
695 /* Prevent warning from -Wmissing-prototypes.  */
696 void _initialize_solib_ia64_hpux (void);
697
698 void
699 _initialize_solib_ia64_hpux (void)
700 {
701   ia64_hpux_so_ops = ia64_hpux_target_so_ops ();
702 }