+/* This operation removes the "hook" between GDB and the dynamic linker,
+ which causes the dld to notify GDB of shared library events.
+
+ After this operation completes, the dld will no longer notify GDB of
+ shared library events. To resume notifications, GDB must call
+ som_solib_create_inferior_hook.
+
+ This operation does not remove any knowledge of shared libraries which
+ GDB may already have been notified of.
+ */
+void
+som_solib_remove_inferior_hook (int pid)
+{
+ CORE_ADDR addr;
+ struct minimal_symbol *msymbol;
+ int status;
+ char dld_flags_buffer[TARGET_INT_BIT / TARGET_CHAR_BIT];
+ unsigned int dld_flags_value;
+ struct cleanup *old_cleanups = save_inferior_ptid ();
+
+ /* Ensure that we're really operating on the specified process. */
+ inferior_ptid = pid_to_ptid (pid);
+
+ /* We won't bother to remove the solib breakpoints from this process.
+
+ In fact, on PA64 the breakpoint is hard-coded into the dld callback,
+ and thus we're not supposed to remove it.
+
+ Rather, we'll merely clear the dld_flags bit that enables callbacks.
+ */
+ msymbol = lookup_minimal_symbol ("__dld_flags", NULL, NULL);
+
+ addr = SYMBOL_VALUE_ADDRESS (msymbol);
+ status = target_read_memory (addr, dld_flags_buffer, TARGET_INT_BIT / TARGET_CHAR_BIT);
+
+ dld_flags_value = extract_unsigned_integer (dld_flags_buffer,
+ sizeof (dld_flags_value));
+
+ dld_flags_value &= ~DLD_FLAGS_HOOKVALID;
+ store_unsigned_integer (dld_flags_buffer,
+ sizeof (dld_flags_value),
+ dld_flags_value);
+ status = target_write_memory (addr, dld_flags_buffer, TARGET_INT_BIT / TARGET_CHAR_BIT);
+
+ do_cleanups (old_cleanups);
+}
+
+
+/* This function creates a breakpoint on the dynamic linker hook, which
+ is called when e.g., a shl_load or shl_unload call is made. This
+ breakpoint will only trigger when a shl_load call is made.
+
+ If filename is NULL, then loads of any dll will be caught. Else,
+ only loads of the file whose pathname is the string contained by
+ filename will be caught.
+
+ Undefined behaviour is guaranteed if this function is called before
+ som_solib_create_inferior_hook.
+ */
+void
+som_solib_create_catch_load_hook (int pid, int tempflag, char *filename,
+ char *cond_string)
+{
+ create_solib_load_event_breakpoint ("__d_trap", tempflag, filename, cond_string);
+}
+
+/* This function creates a breakpoint on the dynamic linker hook, which
+ is called when e.g., a shl_load or shl_unload call is made. This
+ breakpoint will only trigger when a shl_unload call is made.
+
+ If filename is NULL, then unloads of any dll will be caught. Else,
+ only unloads of the file whose pathname is the string contained by
+ filename will be caught.
+
+ Undefined behaviour is guaranteed if this function is called before
+ som_solib_create_inferior_hook.
+ */
+void
+som_solib_create_catch_unload_hook (int pid, int tempflag, char *filename,
+ char *cond_string)
+{
+ create_solib_unload_event_breakpoint ("__d_trap", tempflag, filename, cond_string);
+}
+
+int
+som_solib_have_load_event (int pid)
+{
+ CORE_ADDR event_kind;
+
+ event_kind = read_register (ARG0_REGNUM);
+ return (event_kind == SHL_LOAD);
+}
+
+int
+som_solib_have_unload_event (int pid)
+{
+ CORE_ADDR event_kind;
+
+ event_kind = read_register (ARG0_REGNUM);
+ return (event_kind == SHL_UNLOAD);
+}
+
+static char *
+som_solib_library_pathname (int pid)
+{
+ CORE_ADDR dll_handle_address;
+ CORE_ADDR dll_pathname_address;
+ struct som_solib_mapped_entry dll_descriptor;
+ char *p;
+ static char dll_pathname[1024];
+
+ /* Read the descriptor of this newly-loaded library. */
+ dll_handle_address = read_register (ARG1_REGNUM);
+ read_memory (dll_handle_address, (char *) &dll_descriptor, sizeof (dll_descriptor));
+
+ /* We can find a pointer to the dll's pathname within the descriptor. */
+ dll_pathname_address = (CORE_ADDR) dll_descriptor.name;
+
+ /* Read the pathname, one byte at a time. */
+ p = dll_pathname;
+ for (;;)
+ {
+ char b;
+ read_memory (dll_pathname_address++, (char *) &b, 1);
+ *p++ = b;
+ if (b == '\0')
+ break;
+ }
+
+ return dll_pathname;
+}
+
+char *
+som_solib_loaded_library_pathname (int pid)
+{
+ if (!som_solib_have_load_event (pid))
+ error ("Must have a load event to use this query");
+
+ return som_solib_library_pathname (pid);
+}
+
+char *
+som_solib_unloaded_library_pathname (int pid)
+{
+ if (!som_solib_have_unload_event (pid))
+ error ("Must have an unload event to use this query");
+
+ return som_solib_library_pathname (pid);
+}
+
+static void
+som_solib_desire_dynamic_linker_symbols (void)
+{
+ struct objfile *objfile;
+ struct unwind_table_entry *u;
+ struct minimal_symbol *dld_msymbol;
+
+ /* Do we already know the value of these symbols? If so, then
+ we've no work to do.
+
+ (If you add clauses to this test, be sure to likewise update the
+ test within the loop.)
+ */
+ if (dld_cache.is_valid)
+ return;
+
+ ALL_OBJFILES (objfile)
+ {
+ dld_msymbol = lookup_minimal_symbol ("shl_load", NULL, objfile);
+ if (dld_msymbol != NULL)
+ {
+ dld_cache.load.address = SYMBOL_VALUE (dld_msymbol);
+ dld_cache.load.unwind = find_unwind_entry (dld_cache.load.address);
+ }
+
+ dld_msymbol = lookup_minimal_symbol_solib_trampoline ("shl_load",
+ objfile);
+ if (dld_msymbol != NULL)
+ {
+ if (SYMBOL_TYPE (dld_msymbol) == mst_solib_trampoline)
+ {
+ u = find_unwind_entry (SYMBOL_VALUE (dld_msymbol));
+ if ((u != NULL) && (u->stub_unwind.stub_type == EXPORT))
+ {
+ dld_cache.load_stub.address = SYMBOL_VALUE (dld_msymbol);
+ dld_cache.load_stub.unwind = u;
+ }
+ }
+ }
+
+ dld_msymbol = lookup_minimal_symbol ("shl_unload", NULL, objfile);
+ if (dld_msymbol != NULL)
+ {
+ dld_cache.unload.address = SYMBOL_VALUE (dld_msymbol);
+ dld_cache.unload.unwind = find_unwind_entry (dld_cache.unload.address);
+
+ /* ??rehrauer: I'm not sure exactly what this is, but it appears
+ that on some HPUX 10.x versions, there's two unwind regions to
+ cover the body of "shl_unload", the second being 4 bytes past
+ the end of the first. This is a large hack to handle that
+ case, but since I don't seem to have any legitimate way to
+ look for this thing via the symbol table...
+ */
+ if (dld_cache.unload.unwind != NULL)
+ {
+ u = find_unwind_entry (dld_cache.unload.unwind->region_end + 4);
+ if (u != NULL)
+ {
+ dld_cache.unload2.address = u->region_start;
+ dld_cache.unload2.unwind = u;
+ }
+ }
+ }
+
+ dld_msymbol = lookup_minimal_symbol_solib_trampoline ("shl_unload",
+ objfile);
+ if (dld_msymbol != NULL)
+ {
+ if (SYMBOL_TYPE (dld_msymbol) == mst_solib_trampoline)
+ {
+ u = find_unwind_entry (SYMBOL_VALUE (dld_msymbol));
+ if ((u != NULL) && (u->stub_unwind.stub_type == EXPORT))
+ {
+ dld_cache.unload_stub.address = SYMBOL_VALUE (dld_msymbol);
+ dld_cache.unload_stub.unwind = u;
+ }
+ }
+ }
+
+ /* Did we find everything we were looking for? If so, stop. */
+ if ((dld_cache.load.address != 0)
+ && (dld_cache.load_stub.address != 0)
+ && (dld_cache.unload.address != 0)
+ && (dld_cache.unload_stub.address != 0))
+ {
+ dld_cache.is_valid = 1;
+ break;
+ }
+ }
+
+ dld_cache.hook.unwind = find_unwind_entry (dld_cache.hook.address);
+ dld_cache.hook_stub.unwind = find_unwind_entry (dld_cache.hook_stub.address);
+
+ /* We're prepared not to find some of these symbols, which is why
+ this function is a "desire" operation, and not a "require".
+ */
+}
+
+int
+som_solib_in_dynamic_linker (int pid, CORE_ADDR pc)
+{
+ struct unwind_table_entry *u_pc;
+
+ /* Are we in the dld itself?
+
+ ??rehrauer: Large hack -- We'll assume that any address in a
+ shared text region is the dld's text. This would obviously
+ fall down if the user attached to a process, whose shlibs
+ weren't mapped to a (writeable) private region. However, in
+ that case the debugger probably isn't able to set the fundamental
+ breakpoint in the dld callback anyways, so this hack should be
+ safe.
+ */
+ if ((pc & (CORE_ADDR) 0xc0000000) == (CORE_ADDR) 0xc0000000)
+ return 1;
+
+ /* Cache the address of some symbols that are part of the dynamic
+ linker, if not already known.
+ */
+ som_solib_desire_dynamic_linker_symbols ();
+
+ /* Are we in the dld callback? Or its export stub? */
+ u_pc = find_unwind_entry (pc);
+ if (u_pc == NULL)
+ return 0;
+
+ if ((u_pc == dld_cache.hook.unwind) || (u_pc == dld_cache.hook_stub.unwind))
+ return 1;
+
+ /* Or the interface of the dld (i.e., "shl_load" or friends)? */
+ if ((u_pc == dld_cache.load.unwind)
+ || (u_pc == dld_cache.unload.unwind)
+ || (u_pc == dld_cache.unload2.unwind)
+ || (u_pc == dld_cache.load_stub.unwind)
+ || (u_pc == dld_cache.unload_stub.unwind))
+ return 1;
+
+ /* Apparently this address isn't part of the dld's text. */
+ return 0;
+}
+
+