diff options
author | Natanael Copa <ncopa@alpinelinux.org> | 2010-10-23 10:13:37 +0000 |
---|---|---|
committer | Natanael Copa <ncopa@alpinelinux.org> | 2010-10-23 10:13:37 +0000 |
commit | d666f38c767db33ee765c73fba530d15574effc0 (patch) | |
tree | ba19bb04d5364a2dcfb8d39529de3b4c313aeaf8 /main/gdb/50_all_gdb-pie-1.patch | |
parent | 87342a9d284594791626b251e826c2803a500553 (diff) | |
download | aports-d666f38c767db33ee765c73fba530d15574effc0.tar.bz2 aports-d666f38c767db33ee765c73fba530d15574effc0.tar.xz |
Revert "main/gdb: upgrade to 7.2"
This reverts commit d1c41b447396f63a434d9ca888459cd9b016bbdf.
Diffstat (limited to 'main/gdb/50_all_gdb-pie-1.patch')
-rw-r--r-- | main/gdb/50_all_gdb-pie-1.patch | 1330 |
1 files changed, 1330 insertions, 0 deletions
diff --git a/main/gdb/50_all_gdb-pie-1.patch b/main/gdb/50_all_gdb-pie-1.patch new file mode 100644 index 0000000000..a20771f689 --- /dev/null +++ b/main/gdb/50_all_gdb-pie-1.patch @@ -0,0 +1,1330 @@ +2007-11-02 Jan Kratochvil <jan.kratochvil@redhat.com> + + Port to GDB-6.7.1. + +2007-11-02 Jan Kratochvil <jan.kratochvil@redhat.com> + + Port to post-GDB-6.7.1 multi-PC breakpoints. + +2007-11-09 Jan Kratochvil <jan.kratochvil@redhat.com> + + * solib-svr4.c (svr4_current_sos): Fix segfault on NULL EXEC_BFD. + +2008-02-24 Jan Kratochvil <jan.kratochvil@redhat.com> + + Port to GDB-6.8pre. + +2008-02-27 Jan Kratochvil <jan.kratochvil@redhat.com> + + Port to gdb-6.7.50.20080227. + +Index: gdb/dwarf2read.c +=================================================================== +--- a/gdb/dwarf2read.c 2008-02-27 08:57:20.000000000 +0100 ++++ b/gdb/dwarf2read.c 2008-02-27 08:57:31.000000000 +0100 +@@ -1217,7 +1217,7 @@ dwarf2_build_psymtabs (struct objfile *o + else + dwarf2_per_objfile->loc_buffer = NULL; + +- if (mainline ++ if ((mainline == 1) + || (objfile->global_psymbols.size == 0 + && objfile->static_psymbols.size == 0)) + { +Index: gdb/auxv.c +=================================================================== +--- a/gdb/auxv.c 2008-01-16 17:27:37.000000000 +0100 ++++ b/gdb/auxv.c 2008-02-27 08:57:31.000000000 +0100 +@@ -80,7 +80,7 @@ procfs_xfer_auxv (struct target_ops *ops + Return 1 if an entry was read into *TYPEP and *VALP. */ + int + target_auxv_parse (struct target_ops *ops, gdb_byte **readptr, +- gdb_byte *endptr, CORE_ADDR *typep, CORE_ADDR *valp) ++ gdb_byte *endptr, ULONGEST *typep, CORE_ADDR *valp) + { + const int sizeof_auxv_field = TYPE_LENGTH (builtin_type_void_data_ptr); + gdb_byte *ptr = *readptr; +@@ -105,9 +105,10 @@ target_auxv_parse (struct target_ops *op + an error getting the information. On success, return 1 after + storing the entry's value field in *VALP. */ + int +-target_auxv_search (struct target_ops *ops, CORE_ADDR match, CORE_ADDR *valp) ++target_auxv_search (struct target_ops *ops, ULONGEST match, CORE_ADDR *valp) + { +- CORE_ADDR type, val; ++ CORE_ADDR val; ++ ULONGEST at_type; + gdb_byte *data; + LONGEST n = target_read_alloc (ops, TARGET_OBJECT_AUXV, NULL, &data); + gdb_byte *ptr = data; +@@ -117,10 +118,10 @@ target_auxv_search (struct target_ops *o + return n; + + while (1) +- switch (target_auxv_parse (ops, &ptr, data + n, &type, &val)) ++ switch (target_auxv_parse (ops, &ptr, data + n, &at_type, &val)) + { + case 1: /* Here's an entry, check it. */ +- if (type == match) ++ if (at_type == match) + { + xfree (data); + *valp = val; +@@ -143,7 +144,8 @@ target_auxv_search (struct target_ops *o + int + fprint_target_auxv (struct ui_file *file, struct target_ops *ops) + { +- CORE_ADDR type, val; ++ CORE_ADDR val; ++ ULONGEST at_type; + gdb_byte *data; + LONGEST len = target_read_alloc (ops, TARGET_OBJECT_AUXV, NULL, + &data); +@@ -153,14 +155,14 @@ fprint_target_auxv (struct ui_file *file + if (len <= 0) + return len; + +- while (target_auxv_parse (ops, &ptr, data + len, &type, &val) > 0) ++ while (target_auxv_parse (ops, &ptr, data + len, &at_type, &val) > 0) + { + extern int addressprint; + const char *name = "???"; + const char *description = ""; + enum { dec, hex, str } flavor = hex; + +- switch (type) ++ switch (at_type) + { + #define TAG(tag, text, kind) \ + case tag: name = #tag; description = text; flavor = kind; break +@@ -213,7 +215,7 @@ fprint_target_auxv (struct ui_file *file + } + + fprintf_filtered (file, "%-4s %-20s %-30s ", +- paddr_d (type), name, description); ++ paddr_d (at_type), name, description); + switch (flavor) + { + case dec: +Index: gdb/auxv.h +=================================================================== +--- a/gdb/auxv.h 2008-01-01 23:53:09.000000000 +0100 ++++ b/gdb/auxv.h 2008-02-27 08:57:31.000000000 +0100 +@@ -35,14 +35,14 @@ struct target_ops; /* Forward declarati + Return 1 if an entry was read into *TYPEP and *VALP. */ + extern int target_auxv_parse (struct target_ops *ops, + gdb_byte **readptr, gdb_byte *endptr, +- CORE_ADDR *typep, CORE_ADDR *valp); ++ ULONGEST *typep, CORE_ADDR *valp); + + /* Extract the auxiliary vector entry with a_type matching MATCH. + Return zero if no such entry was found, or -1 if there was + an error getting the information. On success, return 1 after + storing the entry's value field in *VALP. */ + extern int target_auxv_search (struct target_ops *ops, +- CORE_ADDR match, CORE_ADDR *valp); ++ ULONGEST match, CORE_ADDR *valp); + + /* Print the contents of the target's AUXV on the specified file. */ + extern int fprint_target_auxv (struct ui_file *file, struct target_ops *ops); +Index: gdb/breakpoint.h +=================================================================== +--- a/gdb/breakpoint.h 2008-02-01 17:24:46.000000000 +0100 ++++ b/gdb/breakpoint.h 2008-02-27 08:57:31.000000000 +0100 +@@ -144,6 +144,7 @@ enum enable_state + automatically enabled and reset when the call + "lands" (either completes, or stops at another + eventpoint). */ ++ bp_startup_disabled, + bp_permanent /* There is a breakpoint instruction hard-wired into + the target's code. Don't try to write another + breakpoint instruction on top of it, or restore +@@ -823,6 +824,10 @@ extern void remove_thread_event_breakpoi + + extern void disable_breakpoints_in_shlibs (void); + ++extern void disable_breakpoints_at_startup (int silent); ++ ++extern void re_enable_breakpoints_at_startup (void); ++ + /* This function returns TRUE if ep is a catchpoint. */ + extern int ep_is_catchpoint (struct breakpoint *); + +Index: gdb/symfile-mem.c +=================================================================== +--- a/gdb/symfile-mem.c 2008-01-01 23:53:13.000000000 +0100 ++++ b/gdb/symfile-mem.c 2008-02-27 08:57:31.000000000 +0100 +@@ -108,7 +108,7 @@ symbol_file_add_from_memory (struct bfd + } + + objf = symbol_file_add_from_bfd (nbfd, from_tty, +- sai, 0, OBJF_SHARED); ++ sai, 2, OBJF_SHARED); + + /* This might change our ideas about frames already looked at. */ + reinit_frame_cache (); +Index: gdb/infrun.c +=================================================================== +--- a/gdb/infrun.c 2008-02-27 08:57:20.000000000 +0100 ++++ b/gdb/infrun.c 2008-02-27 08:57:31.000000000 +0100 +@@ -2277,6 +2277,11 @@ process_event_stop_test: + #endif + target_terminal_inferior (); + ++ /* For PIE executables, we dont really know where the ++ breakpoints are going to be until we start up the ++ inferior. */ ++ re_enable_breakpoints_at_startup (); ++ + /* If requested, stop when the dynamic linker notifies + gdb of events. This allows the user to get control + and place breakpoints in initializer routines for +Index: gdb/objfiles.c +=================================================================== +--- a/gdb/objfiles.c 2008-01-01 23:53:12.000000000 +0100 ++++ b/gdb/objfiles.c 2008-02-27 08:57:31.000000000 +0100 +@@ -49,6 +49,9 @@ + #include "source.h" + #include "addrmap.h" + ++#include "auxv.h" ++#include "elf/common.h" ++ + /* Prototypes for local functions */ + + static void objfile_alloc_data (struct objfile *objfile); +@@ -260,7 +263,19 @@ init_entry_point_info (struct objfile *o + CORE_ADDR + entry_point_address (void) + { +- return symfile_objfile ? symfile_objfile->ei.entry_point : 0; ++ int ret; ++ CORE_ADDR entry_addr; ++ ++ /* Find the address of the entry point of the program from the ++ auxv vector. */ ++ ret = target_auxv_search (¤t_target, AT_ENTRY, &entry_addr); ++ if (ret == 1) ++ return entry_addr; ++ /*if (ret == 0 || ret == -1)*/ ++ else ++ { ++ return symfile_objfile ? symfile_objfile->ei.entry_point : 0; ++ } + } + + /* Create the terminating entry of OBJFILE's minimal symbol table. +Index: gdb/solib-svr4.c +=================================================================== +--- a/gdb/solib-svr4.c 2008-02-27 08:57:19.000000000 +0100 ++++ b/gdb/solib-svr4.c 2008-02-27 08:59:06.000000000 +0100 +@@ -31,6 +31,8 @@ + #include "gdbcore.h" + #include "target.h" + #include "inferior.h" ++#include "auxv.h" ++#include "command.h" + + #include "gdb_assert.h" + +@@ -246,7 +248,9 @@ static char *debug_loader_name; + + /* Local function prototypes */ + ++#if 0 + static int match_main (char *); ++#endif + + static CORE_ADDR bfd_lookup_symbol (bfd *, char *); + +@@ -349,10 +353,12 @@ scan_dyntag (int dyntag, bfd *abfd, CORE + int arch_size, step, sect_size; + long dyn_tag; + CORE_ADDR dyn_ptr, dyn_addr; ++ CORE_ADDR entry_addr; + gdb_byte *bufend, *bufstart, *buf; + Elf32_External_Dyn *x_dynp_32; + Elf64_External_Dyn *x_dynp_64; + struct bfd_section *sect; ++ int ret; + + if (abfd == NULL) + return 0; +@@ -360,19 +366,74 @@ scan_dyntag (int dyntag, bfd *abfd, CORE + if (arch_size == -1) + return 0; + ++ /* The auxv vector based relocatable files reading is limited to the main ++ executable. */ ++ gdb_assert (abfd == exec_bfd || ptr == NULL); ++ ++ if (ptr != NULL) ++ { ++ /* Find the address of the entry point of the program from the ++ auxv vector. */ ++ ret = target_auxv_search (¤t_target, AT_ENTRY, &entry_addr); ++ ++ if (ret == 0 || ret == -1) ++ { ++ /* No auxv info, maybe an older kernel. Fake our way through. */ ++ entry_addr = bfd_get_start_address (exec_bfd); ++ ++ if (debug_solib) ++ fprintf_unfiltered (gdb_stdlog, ++ "elf_locate_base: program entry address not found. Using bfd's 0x%s for %s\n", ++ paddr_nz (entry_addr), exec_bfd->filename); ++ } ++ else ++ { ++ if (debug_solib) ++ fprintf_unfiltered (gdb_stdlog, ++ "elf_locate_base: found program entry address 0x%s for %s\n", ++ paddr_nz (entry_addr), exec_bfd->filename); ++ } ++ } ++ + /* Find the start address of the .dynamic section. */ + sect = bfd_get_section_by_name (abfd, ".dynamic"); + if (sect == NULL) +- return 0; ++ { ++ if (debug_solib) ++ fprintf_unfiltered (gdb_stdlog, ++ "elf_locate_base: .dynamic section not found in %s -- return now\n", ++ exec_bfd->filename); ++ return 0; ++ } ++ else ++ { ++ if (debug_solib) ++ fprintf_unfiltered (gdb_stdlog, ++ "elf_locate_base: .dynamic section found in %s\n", ++ exec_bfd->filename); ++ } ++ + dyn_addr = bfd_section_vma (abfd, sect); ++ if (debug_solib) ++ fprintf_unfiltered (gdb_stdlog, ++ "elf_locate_base: .dynamic addr 0x%s\n", ++ paddr_nz (dyn_addr)); + + /* Read in .dynamic from the BFD. We will get the actual value + from memory later. */ + sect_size = bfd_section_size (abfd, sect); + buf = bufstart = alloca (sect_size); ++ if (debug_solib) ++ fprintf_unfiltered (gdb_stdlog, ++ "elf_locate_base: read in .dynamic section\n"); + if (!bfd_get_section_contents (abfd, sect, + buf, 0, sect_size)) +- return 0; ++ { ++ if (debug_solib) ++ fprintf_unfiltered (gdb_stdlog, ++ "elf_locate_base: couldn't read .dynamic section -- return now\n"); ++ return 0; ++ } + + /* Iterate over BUF and scan for DYNTAG. If found, set PTR and return. */ + step = (arch_size == 32) ? sizeof (Elf32_External_Dyn) +@@ -405,9 +466,43 @@ scan_dyntag (int dyntag, bfd *abfd, CORE + CORE_ADDR ptr_addr; + + ptr_addr = dyn_addr + (buf - bufstart) + arch_size / 8; ++ if (ptr != NULL) ++ { ++ if (debug_solib) ++ fprintf_unfiltered (gdb_stdlog, ++ "elf_locate_base: unrelocated ptr addr 0x%s\n", ++ paddr_nz (ptr_addr)); ++ ptr_addr += entry_addr - bfd_get_start_address (exec_bfd); ++ if (debug_solib) ++ fprintf_unfiltered (gdb_stdlog, ++ "elf_locate_base: relocated ptr addr 0x%s" ++ " (auxv entry 0x%s, bfd start address 0x%s)" ++ " for %s\n", ++ paddr_nz (ptr_addr), paddr_nz (entry_addr), ++ paddr_nz (bfd_get_start_address (exec_bfd)), ++ exec_bfd->filename); ++ } + if (target_read_memory (ptr_addr, ptr_buf, arch_size / 8) == 0) +- dyn_ptr = extract_typed_address (ptr_buf, +- builtin_type_void_data_ptr); ++ { ++ dyn_ptr = extract_typed_address (ptr_buf, ++ builtin_type_void_data_ptr); ++ if (ptr != NULL) ++ { ++ if (debug_solib) ++ fprintf_unfiltered (gdb_stdlog, ++ "elf_locate_base: Tag entry has value 0x%s -- return now\n", ++ paddr_nz (dyn_ptr)); ++ } ++ } ++ else ++ { ++ if (ptr != NULL) ++ { ++ if (debug_solib) ++ fprintf_unfiltered (gdb_stdlog, ++ "elf_locate_base: Couldn't read tag entry value -- return now\n"); ++ } ++ } + *ptr = dyn_ptr; + } + return 1; +@@ -544,6 +639,10 @@ solib_svr4_r_map (void) + { + struct link_map_offsets *lmo = svr4_fetch_link_map_offsets (); + ++ if (debug_solib) ++ fprintf_unfiltered (gdb_stdlog, ++ "solib_svr4_r_map: read at 0x%s\n", ++ paddr_nz (debug_base + lmo->r_map_offset)); + return read_memory_typed_address (debug_base + lmo->r_map_offset, + builtin_type_void_data_ptr); + } +@@ -713,6 +812,11 @@ svr4_current_sos (void) + struct so_list *head = 0; + struct so_list **link_ptr = &head; + CORE_ADDR ldsomap = 0; ++ const char *filename = exec_bfd ? exec_bfd->filename : "<none>"; ++ ++ if (debug_solib) ++ fprintf_unfiltered (gdb_stdlog, ++ "svr4_current_sos: exec_bfd %s\n", filename); + + /* Always locate the debug struct, in case it has moved. */ + debug_base = 0; +@@ -721,10 +825,19 @@ svr4_current_sos (void) + /* If we can't find the dynamic linker's base structure, this + must not be a dynamically linked executable. Hmm. */ + if (! debug_base) +- return svr4_default_sos (); ++ { ++ if (debug_solib) ++ fprintf_unfiltered (gdb_stdlog, ++ "svr4_current_sos: no DT_DEBUG found in %s -- return now\n", ++ filename); ++ return svr4_default_sos (); ++ } + + /* Walk the inferior's link map list, and build our list of + `struct so_list' nodes. */ ++ if (debug_solib) ++ fprintf_unfiltered (gdb_stdlog, ++ "svr4_current_sos: walk link map in %s\n", filename); + lm = solib_svr4_r_map (); + + while (lm) +@@ -740,23 +853,103 @@ svr4_current_sos (void) + new->lm_info->lm = xzalloc (lmo->link_map_size); + make_cleanup (xfree, new->lm_info->lm); + ++ if (debug_solib) ++ fprintf_unfiltered (gdb_stdlog, ++ "svr4_current_sos: read lm at 0x%s\n", paddr_nz(lm)); + read_memory (lm, new->lm_info->lm, lmo->link_map_size); + + lm = LM_NEXT (new); + ++ if (debug_solib) ++ fprintf_unfiltered (gdb_stdlog, ++ "svr4_current_sos: is first link entry? %d\n", ++ IGNORE_FIRST_LINK_MAP_ENTRY (new)); ++ + /* For SVR4 versions, the first entry in the link map is for the + inferior executable, so we must ignore it. For some versions of + SVR4, it has no name. For others (Solaris 2.3 for example), it + does have a name, so we can no longer use a missing name to + decide when to ignore it. */ +- if (IGNORE_FIRST_LINK_MAP_ENTRY (new) && ldsomap == 0) +- free_so (new); ++ if (exec_bfd != NULL && IGNORE_FIRST_LINK_MAP_ENTRY (new) && ldsomap == 0) ++ { ++ /* It is the first link map entry, i.e. it is the main executable. */ ++ ++ if (bfd_get_start_address (exec_bfd) == entry_point_address ()) ++ { ++ /* Non-pie case, main executable has not been relocated. */ ++ free_so (new); ++ } ++ else ++ { ++ /* Pie case, main executable has been relocated. */ ++ struct so_list *gdb_solib; ++ ++ if (debug_solib) ++ fprintf_unfiltered (gdb_stdlog, ++ "svr4_current_sos: Processing first link map entry\n"); ++ strncpy (new->so_name, exec_bfd->filename, ++ SO_NAME_MAX_PATH_SIZE - 1); ++ new->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0'; ++ strcpy (new->so_original_name, new->so_name); ++ /*new->main = 1;*/ ++ new->main_relocated = 0; ++ ++ if (debug_solib) ++ { ++ fprintf_unfiltered (gdb_stdlog, ++ "svr4_current_sos: Processing nameless DSO\n"); ++ fprintf_unfiltered (gdb_stdlog, ++ "svr4_current_sos: adding name %s\n", ++ new->so_name); ++ } ++ ++ for (gdb_solib = master_so_list (); ++ gdb_solib; ++ gdb_solib = gdb_solib->next) ++ { ++ if (debug_solib) ++ fprintf_unfiltered (gdb_stdlog, ++ "svr4_current_sos: compare gdb %s and new %s\n", ++ gdb_solib->so_name, new->so_name); ++ if (strcmp (gdb_solib->so_name, new->so_name) == 0) ++ if (gdb_solib->main_relocated) ++ { ++ if (debug_solib) ++ fprintf_unfiltered (gdb_stdlog, ++ "svr4_current_sos: found main relocated\n"); ++ break; ++ } ++ } ++ ++ if ((gdb_solib && !gdb_solib->main_relocated) || (!gdb_solib)) ++ { ++ add_to_target_sections (0 /*from_tty*/, ¤t_target, new); ++ new->main = 1; ++ } ++ ++ /* We need this in the list of shared libs we return because ++ solib_add_stub will loop through it and add the symbol file. */ ++ new->next = 0; ++ *link_ptr = new; ++ link_ptr = &new->next; ++ } ++ } /* End of IGNORE_FIRST_LINK_MAP_ENTRY */ + else + { ++ /* This is not the first link map entry, i.e. is not the main ++ executable. Note however that it could be the DSO supplied on ++ certain systems (i.e. Linux 2.6) containing information about ++ the vsyscall page. We must ignore such entry. This entry is ++ nameless (just like the one for the main executable, sigh). */ ++ + int errcode; + char *buffer; + + /* Extract this shared object's name. */ ++ if (debug_solib) ++ fprintf_unfiltered (gdb_stdlog, ++ "svr4_current_sos: read LM_NAME\n"); ++ + target_read_string (LM_NAME (new), &buffer, + SO_NAME_MAX_PATH_SIZE - 1, &errcode); + if (errcode != 0) +@@ -764,23 +957,35 @@ svr4_current_sos (void) + safe_strerror (errcode)); + else + { +- strncpy (new->so_name, buffer, SO_NAME_MAX_PATH_SIZE - 1); +- new->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0'; +- strcpy (new->so_original_name, new->so_name); +- } +- xfree (buffer); +- +- /* If this entry has no name, or its name matches the name +- for the main executable, don't include it in the list. */ +- if (! new->so_name[0] +- || match_main (new->so_name)) +- free_so (new); +- else +- { +- new->next = 0; +- *link_ptr = new; +- link_ptr = &new->next; ++ if (debug_solib) ++ fprintf_unfiltered (gdb_stdlog, ++ "svr4_current_sos: LM_NAME is <%s>\n", ++ buffer); ++ /* The name could be empty, in which case it is the ++ system supplied DSO. */ ++ if (strcmp (buffer, "") == 0) ++ free_so (new); ++ else ++ { ++ strncpy (new->so_name, buffer, SO_NAME_MAX_PATH_SIZE - 1); ++ new->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0'; ++ strcpy (new->so_original_name, new->so_name); ++ if (debug_solib) ++ { ++ fprintf_unfiltered (gdb_stdlog, ++ "svr4_current_sos: Processing DSO: %s\n", ++ new->so_name); ++ fprintf_unfiltered (gdb_stdlog, ++ "svr4_current_sos: first link entry %d\n", ++ IGNORE_FIRST_LINK_MAP_ENTRY (new)); ++ } ++ ++ new->next = 0; ++ *link_ptr = new; ++ link_ptr = &new->next; ++ } + } ++ xfree (buffer); + } + + /* On Solaris, the dynamic linker is not in the normal list of +@@ -796,6 +1001,9 @@ svr4_current_sos (void) + if (head == NULL) + return svr4_default_sos (); + ++ if (debug_solib) ++ fprintf_unfiltered (gdb_stdlog, "svr4_current_sos: ENDS %s\n", filename); ++ + return head; + } + +@@ -875,7 +1083,7 @@ svr4_fetch_objfile_link_map (struct objf + /* On some systems, the only way to recognize the link map entry for + the main executable file is by looking at its name. Return + non-zero iff SONAME matches one of the known main executable names. */ +- ++#if 0 + static int + match_main (char *soname) + { +@@ -889,6 +1097,7 @@ match_main (char *soname) + + return (0); + } ++#endif + + /* Return 1 if PC lies in the dynamic symbol resolution code of the + SVR4 run time loader. */ +@@ -1040,6 +1249,11 @@ enable_break (void) + /* Find the .interp section; if not found, warn the user and drop + into the old breakpoint at symbol code. */ + interp_sect = bfd_get_section_by_name (exec_bfd, ".interp"); ++ ++ if (debug_solib) ++ fprintf_unfiltered (gdb_stdlog, ++ "enable_break: search for .interp in %s\n", ++ exec_bfd->filename); + if (interp_sect) + { + unsigned int interp_sect_size; +@@ -1074,6 +1288,9 @@ enable_break (void) + if (tmp_fd >= 0) + tmp_bfd = bfd_fopen (tmp_pathname, gnutarget, FOPEN_RB, tmp_fd); + ++ if (debug_solib) ++ fprintf_unfiltered (gdb_stdlog, ++ "enable_break: opening %s\n", tmp_pathname); + if (tmp_bfd == NULL) + goto bkpt_at_symbol; + +@@ -1180,6 +1397,9 @@ enable_break (void) + if (sym_addr != 0) + { + create_solib_event_breakpoint (load_addr + sym_addr); ++ if (debug_solib) ++ fprintf_unfiltered (gdb_stdlog, ++ "enable_break: solib bp set\n"); + return 1; + } + +@@ -1440,6 +1660,8 @@ svr4_solib_create_inferior_hook (void) + while (stop_signal != TARGET_SIGNAL_TRAP); + stop_soon = NO_STOP_QUIETLY; + #endif /* defined(_SCO_DS) */ ++ ++ disable_breakpoints_at_startup (1); + } + + static void +@@ -1620,6 +1842,75 @@ svr4_lp64_fetch_link_map_offsets (void) + + return lmp; + } ++void ++info_linkmap_command (char *cmd, int from_tty) ++{ ++ CORE_ADDR lm; ++ ++ /* Make sure we've looked up the inferior's dynamic linker's base ++ structure. */ ++ if (! debug_base) ++ { ++ debug_base = locate_base (); ++ ++ /* If we can't find the dynamic linker's base structure, this ++ must not be a dynamically linked executable. Hmm. */ ++ if (! debug_base) ++ { ++ if (debug_solib) ++ fprintf_unfiltered (gdb_stdlog, ++ "svr4_print_linkmap: no DT_DEBUG found in %s -- return now\n", ++ exec_bfd->filename); ++ return; ++ } ++ } ++ ++ /* Walk the inferior's link map list, and print the info. */ ++ ++ lm = solib_svr4_r_map (); ++ while (lm) ++ { ++ int errcode; ++ char *buffer; ++ CORE_ADDR load_addr; ++ ++ struct link_map_offsets *lmo = svr4_fetch_link_map_offsets (); ++ struct so_list *new ++ = (struct so_list *) xmalloc (sizeof (struct so_list)); ++ struct cleanup *old_chain = make_cleanup (xfree, new); ++ ++ memset (new, 0, sizeof (*new)); ++ ++ new->lm_info = xmalloc (sizeof (struct lm_info)); ++ make_cleanup (xfree, new->lm_info); ++ ++ new->lm_info->lm = xmalloc (lmo->link_map_size); ++ make_cleanup (xfree, new->lm_info->lm); ++ memset (new->lm_info->lm, 0, lmo->link_map_size); ++ ++ if (debug_solib) ++ fprintf_unfiltered (gdb_stdlog, ++ "svr4_print_linkmap: read lm at 0x%s\n", paddr_nz(lm)); ++ read_memory (lm, new->lm_info->lm, lmo->link_map_size); ++ ++ lm = LM_NEXT (new); ++ ++ /* Load address. */ ++ load_addr = LM_ADDR_CHECK (new, NULL); ++ /* Shared object's name. */ ++ target_read_string (LM_NAME (new), &buffer, ++ SO_NAME_MAX_PATH_SIZE - 1, &errcode); ++ make_cleanup (xfree, buffer); ++ if (errcode != 0) ++ { ++ warning ("svr4_print_linkmap: Can't read pathname for load map: %s\n", ++ safe_strerror (errcode)); ++ } ++ fprintf_filtered (gdb_stdout, "%-8s %-30s\n", paddr(load_addr), buffer); ++ do_cleanups (old_chain); ++ } ++} ++ + + + struct target_so_ops svr4_so_ops; +@@ -1678,4 +1969,7 @@ _initialize_svr4_solib (void) + svr4_so_ops.in_dynsym_resolve_code = svr4_in_dynsym_resolve_code; + svr4_so_ops.lookup_lib_global_symbol = elf_lookup_lib_symbol; + svr4_so_ops.same = svr4_same; ++ ++ add_info ("linkmap", info_linkmap_command, ++ "Display the inferior's linkmap."); + } +Index: gdb/varobj.c +=================================================================== +--- a/gdb/varobj.c 2008-02-04 08:49:04.000000000 +0100 ++++ b/gdb/varobj.c 2008-02-27 08:57:31.000000000 +0100 +@@ -1078,6 +1078,62 @@ install_new_value (struct varobj *var, s + return changed; + } + ++void ++varobj_refresh (void) ++{ ++ struct varobj *var; ++ struct varobj_root *croot; ++ int mycount = rootcount; ++ char * name; ++ ++ croot = rootlist; ++ while ((croot != NULL) && (mycount > 0)) ++ { ++ var = croot->rootvar; ++ ++ /* Get rid of the memory for the old expression. This also ++ leaves var->root->exp == NULL, which is ok for the parsing ++ below. */ ++ free_current_contents (&var->root->exp); ++ ++ value_free (var->value); ++ var->type = NULL; ++ ++ name = xstrdup (var->name); ++ ++ /* Reparse the expression. Wrap the call to parse expression, ++ so we can return a sensible error. */ ++ if (!gdb_parse_exp_1 (&name, var->root->valid_block, 0, &var->root->exp)) ++ { ++ return; ++ } ++ ++ /* We definitively need to catch errors here. ++ If evaluate_expression succeeds we got the value we wanted. ++ But if it fails, we still go on with a call to evaluate_type() */ ++ if (gdb_evaluate_expression (var->root->exp, &var->value)) ++ { ++ /* no error */ ++ release_value (var->value); ++ if (value_lazy (var->value)) ++ gdb_value_fetch_lazy (var->value); ++ } ++ else ++ var->value = evaluate_type (var->root->exp); ++ ++ var->type = value_type (var->value); ++ ++ mycount--; ++ croot = croot->next; ++ } ++ ++ if (mycount || (croot != NULL)) ++ warning ++ ("varobj_refresh: assertion failed - wrong tally of root vars (%d:%d)", ++ rootcount, mycount); ++} ++ ++ + /* Update the values for a variable and its children. This is a + two-pronged attack. First, re-parse the value for the root's + expression to see if it's changed. Then go all the way +Index: gdb/solist.h +=================================================================== +--- a/gdb/solist.h 2008-01-07 16:19:58.000000000 +0100 ++++ b/gdb/solist.h 2008-02-27 08:57:31.000000000 +0100 +@@ -61,6 +61,8 @@ struct so_list + bfd *abfd; + char symbols_loaded; /* flag: symbols read in yet? */ + char from_tty; /* flag: print msgs? */ ++ char main; /* flag: is this the main executable? */ ++ char main_relocated; /* flag: has it been relocated yet? */ + struct objfile *objfile; /* objfile for loaded lib */ + struct section_table *sections; + struct section_table *sections_end; +@@ -127,9 +129,15 @@ void free_so (struct so_list *so); + /* Return address of first so_list entry in master shared object list. */ + struct so_list *master_so_list (void); + ++/* Return address of first so_list entry in master shared object list. */ ++struct so_list *master_so_list (void); ++ + /* Find solib binary file and open it. */ + extern int solib_open (char *in_pathname, char **found_pathname); + ++/* Add the list of sections in so_list to the target to_sections. */ ++extern void add_to_target_sections (int, struct target_ops *, struct so_list *); ++ + /* FIXME: gdbarch needs to control this variable */ + extern struct target_so_ops *current_target_so_ops; + +@@ -140,4 +148,6 @@ struct symbol *solib_global_lookup (cons + const domain_enum domain, + struct symtab **symtab); + ++/* Controls the printing of debugging output. */ ++extern int debug_solib; + #endif +Index: gdb/varobj.h +=================================================================== +--- a/gdb/varobj.h 2008-01-30 08:17:31.000000000 +0100 ++++ b/gdb/varobj.h 2008-02-27 08:57:31.000000000 +0100 +@@ -122,4 +122,6 @@ extern void varobj_invalidate (void); + + extern int varobj_editable_p (struct varobj *var); + ++extern void varobj_refresh(void); ++ + #endif /* VAROBJ_H */ +Index: gdb/symfile.c +=================================================================== +--- a/gdb/symfile.c 2008-01-29 23:47:20.000000000 +0100 ++++ b/gdb/symfile.c 2008-02-27 08:57:31.000000000 +0100 +@@ -47,6 +47,7 @@ + #include "readline/readline.h" + #include "gdb_assert.h" + #include "block.h" ++#include "varobj.h" + #include "observer.h" + #include "exec.h" + #include "parser-defs.h" +@@ -778,7 +779,7 @@ syms_from_objfile (struct objfile *objfi + + /* Now either addrs or offsets is non-zero. */ + +- if (mainline) ++ if (mainline == 1) + { + /* We will modify the main symbol table, make sure that all its users + will be cleaned up if an error occurs during symbol reading. */ +@@ -806,7 +807,7 @@ syms_from_objfile (struct objfile *objfi + + We no longer warn if the lowest section is not a text segment (as + happens for the PA64 port. */ +- if (!mainline && addrs && addrs->other[0].name) ++ if (/*!mainline &&*/ addrs && addrs->other[0].name) + { + asection *lower_sect; + asection *sect; +@@ -975,17 +976,21 @@ new_symfile_objfile (struct objfile *obj + /* If this is the main symbol file we have to clean up all users of the + old main symbol file. Otherwise it is sufficient to fixup all the + breakpoints that may have been redefined by this symbol file. */ +- if (mainline) ++ if (mainline == 1) + { + /* OK, make it the "real" symbol file. */ + symfile_objfile = objfile; + + clear_symtab_users (); + } +- else ++ else if (mainline == 0) + { + breakpoint_re_set (); + } ++ else ++ { ++ /* Don't reset breakpoints or it will screw up PIE. */ ++ } + + /* We're done reading the symbol file; finish off complaints. */ + clear_complaints (&symfile_complaints, 0, verbo); +@@ -1028,7 +1033,7 @@ symbol_file_add_with_addrs_or_offsets (b + interactively wiping out any existing symbols. */ + + if ((have_full_symbols () || have_partial_symbols ()) +- && mainline ++ && (mainline == 1) + && from_tty + && !query ("Load new symbol table from \"%s\"? ", name)) + error (_("Not confirmed.")); +@@ -1212,6 +1217,10 @@ symbol_file_clear (int from_tty) + symfile_objfile->name) + : !query (_("Discard symbol table? ")))) + error (_("Not confirmed.")); ++#ifdef CLEAR_SOLIB ++ CLEAR_SOLIB (); ++#endif ++ + free_all_objfiles (); + + /* solib descriptors may have handles to objfiles. Since their +@@ -2466,6 +2475,8 @@ reread_symbols (void) + /* Discard cleanups as symbol reading was successful. */ + discard_cleanups (old_cleanups); + ++ init_entry_point_info (objfile); ++ + /* If the mtime has changed between the time we set new_modtime + and now, we *want* this to be out of date, so don't call stat + again now. */ +@@ -2834,6 +2845,7 @@ clear_symtab_users (void) + breakpoint_re_set (); + set_default_breakpoint (0, 0, 0, 0); + clear_pc_function_cache (); ++ varobj_refresh (); + observer_notify_new_objfile (NULL); + + /* Clear globals which might have pointed into a removed objfile. +Index: gdb/breakpoint.c +=================================================================== +--- a/gdb/breakpoint.c 2008-02-27 08:57:20.000000000 +0100 ++++ b/gdb/breakpoint.c 2008-02-27 08:57:31.000000000 +0100 +@@ -923,7 +923,7 @@ update_watchpoint (struct breakpoint *b, + value_release_to_mark (mark); + + /* Look at each value on the value chain. */ +- for (; v; v = next) ++ for (; v; v = value_next (v)) + { + /* If it's a memory location, and GDB actually needed + its contents to evaluate the expression, then we +@@ -3882,7 +3882,8 @@ describe_other_breakpoints (CORE_ADDR pc + printf_filtered (" (thread %d)", b->thread); + printf_filtered ("%s%s ", + ((b->enable_state == bp_disabled || +- b->enable_state == bp_call_disabled) ++ b->enable_state == bp_call_disabled || ++ b->enable_state == bp_startup_disabled) + ? " (disabled)" + : b->enable_state == bp_permanent + ? " (permanent)" +@@ -4534,6 +4535,62 @@ disable_breakpoints_in_unloaded_shlib (s + } + } + ++void ++disable_breakpoints_at_startup (int silent) ++{ ++ struct breakpoint *b; ++ int disabled_startup_breaks = 0; ++ ++ if (bfd_get_start_address (exec_bfd) != entry_point_address ()) ++ { ++ ALL_BREAKPOINTS (b) ++ { ++ if (((b->type == bp_breakpoint) || ++ (b->type == bp_hardware_breakpoint)) && ++ b->enable_state == bp_enabled && ++ !b->loc->duplicate) ++ { ++ b->enable_state = bp_startup_disabled; ++ if (!silent) ++ { ++ if (!disabled_startup_breaks) ++ { ++ target_terminal_ours_for_output (); ++ warning ("Temporarily disabling breakpoints:"); ++ } ++ disabled_startup_breaks = 1; ++ warning ("breakpoint #%d addr 0x%s", b->number, paddr_nz(b->loc->address)); ++ } ++ } ++ } ++ } ++} ++ ++/* Try to reenable any breakpoints after startup. */ ++void ++re_enable_breakpoints_at_startup (void) ++{ ++ struct breakpoint *b; ++ ++ if (bfd_get_start_address (exec_bfd) != entry_point_address ()) ++ { ++ ALL_BREAKPOINTS (b) ++ if (b->enable_state == bp_startup_disabled) ++ { ++ char buf[1]; ++ ++ /* Do not reenable the breakpoint if the shared library ++ is still not mapped in. */ ++ if (target_read_memory (b->loc->address, buf, 1) == 0) ++ { ++ /*printf ("enabling breakpoint at 0x%s\n", paddr_nz(b->loc->address));*/ ++ b->enable_state = bp_enabled; ++ } ++ } ++ } ++} ++ ++ + static void + create_fork_vfork_event_catchpoint (int tempflag, char *cond_string, + enum bptype bp_kind) +Index: gdb/solib.c +=================================================================== +--- a/gdb/solib.c 2008-01-07 16:19:58.000000000 +0100 ++++ b/gdb/solib.c 2008-02-27 08:57:31.000000000 +0100 +@@ -79,6 +79,8 @@ set_solib_ops (struct gdbarch *gdbarch, + + /* external data declarations */ + ++int debug_solib; ++ + /* FIXME: gdbarch needs to control this variable, or else every + configuration needs to call set_solib_ops. */ + struct target_so_ops *current_target_so_ops; +@@ -102,6 +104,8 @@ The search path for loading non-absolute + value); + } + ++void add_to_target_sections (int, struct target_ops *, struct so_list *); ++ + /* + + GLOBAL FUNCTION +@@ -391,7 +395,6 @@ free_so (struct so_list *so) + xfree (so); + } + +- + /* Return address of first so_list entry in master shared object list. */ + struct so_list * + master_so_list (void) +@@ -399,7 +402,6 @@ master_so_list (void) + return so_list_head; + } + +- + /* A small stub to get us past the arg-passing pinhole of catch_errors. */ + + static int +@@ -411,15 +413,40 @@ symbol_add_stub (void *arg) + /* Have we already loaded this shared object? */ + ALL_OBJFILES (so->objfile) + { +- if (strcmp (so->objfile->name, so->so_name) == 0) ++ /* Found an already loaded shared library. */ ++ if (strcmp (so->objfile->name, so->so_name) == 0 ++ && !so->main) + return 1; ++ /* Found an already loaded main executable. This could happen in ++ two circumstances. ++ First case: the main file has already been read in ++ as the first thing that gdb does at startup, and the file ++ hasn't been relocated properly yet. Therefor we need to read ++ it in with the proper section info. ++ Second case: it has been read in with the correct relocation, ++ and therefore we need to skip it. */ ++ if (strcmp (so->objfile->name, so->so_name) == 0 ++ && so->main ++ && so->main_relocated) ++ return 1; + } + + sap = build_section_addr_info_from_section_table (so->sections, + so->sections_end); + +- so->objfile = symbol_file_add (so->so_name, so->from_tty, +- sap, 0, OBJF_SHARED); ++ if (so->main) ++ { ++ if (debug_solib) ++ fprintf_unfiltered (gdb_stdlog, ++ "symbol_add_stub: adding symbols for main\n"); ++ so->objfile = symbol_file_add (so->so_name, /*so->from_tty*/ 0, ++ sap, 1, 0); ++ so->main_relocated = 1; ++ } ++ else ++ so->objfile = symbol_file_add (so->so_name, so->from_tty, ++ sap, 0, OBJF_SHARED); ++ + free_section_addr_info (sap); + + return (1); +@@ -545,6 +572,10 @@ update_solib_list (int from_tty, struct + } + else + { ++ if (debug_solib) ++ fprintf_unfiltered (gdb_stdlog, ++ "update_solib_list: compare gdb:%s and inferior:%s\n", ++ gdb->so_original_name, i->so_original_name); + if (! strcmp (gdb->so_original_name, i->so_original_name)) + break; + } +@@ -599,28 +630,7 @@ update_solib_list (int from_tty, struct + /* Fill in the rest of each of the `struct so_list' nodes. */ + for (i = inferior; i; i = i->next) + { +- i->from_tty = from_tty; +- +- /* Fill in the rest of the `struct so_list' node. */ +- catch_errors (solib_map_sections, i, +- "Error while mapping shared library sections:\n", +- RETURN_MASK_ALL); +- +- /* If requested, add the shared object's sections to the TARGET's +- section table. Do this immediately after mapping the object so +- that later nodes in the list can query this object, as is needed +- in solib-osf.c. */ +- if (target) +- { +- int count = (i->sections_end - i->sections); +- if (count > 0) +- { +- int space = target_resize_to_sections (target, count); +- memcpy (target->to_sections + space, +- i->sections, +- count * sizeof (i->sections[0])); +- } +- } ++ add_to_target_sections (from_tty, target, i); + + /* Notify any observer that the shared object has been + loaded now that we've added it to GDB's tables. */ +@@ -716,6 +726,41 @@ solib_add (char *pattern, int from_tty, + } + } + ++void ++add_to_target_sections (int from_tty, struct target_ops *target, struct so_list *solib) ++{ ++ /* If this is set, then the sections have been already added to the ++ target list. */ ++ if (solib->main) ++ return; ++ ++ solib->from_tty = from_tty; ++ ++ /* Fill in the rest of the `struct so_list' node. */ ++ catch_errors (solib_map_sections, solib, ++ "Error while mapping shared library sections:\n", ++ RETURN_MASK_ALL); ++ ++ /* If requested, add the shared object's sections to the TARGET's ++ section table. Do this immediately after mapping the object so ++ that later nodes in the list can query this object, as is needed ++ in solib-osf.c. */ ++ if (target) ++ { ++ int count = (solib->sections_end - solib->sections); ++ if (count > 0) ++ { ++ int space = target_resize_to_sections (target, count); ++ if (debug_solib) ++ fprintf_unfiltered (gdb_stdlog, ++ "add_to_target_sections: add %s to to_sections\n", ++ solib->so_original_name); ++ memcpy (target->to_sections + space, ++ solib->sections, ++ count * sizeof (solib->sections[0])); ++ } ++ } ++} + + /* + +@@ -1035,4 +1080,12 @@ This takes precedence over the environme + reload_shared_libraries, + show_solib_search_path, + &setlist, &showlist); ++ ++ add_setshow_boolean_cmd ("solib", no_class, &debug_solib, ++ _("\ ++Set debugging of GNU/Linux shlib module.\n"), _("\ ++Show debugging status of GNU/Linux shlib module.\n"), _("\ ++Enables printf debugging output of GNU/Linux shlib module.\n"), ++ NULL, NULL, ++ &setdebuglist, &showdebuglist); + } +Index: gdb/elfread.c +=================================================================== +--- a/gdb/elfread.c 2008-01-01 23:53:09.000000000 +0100 ++++ b/gdb/elfread.c 2008-02-27 08:57:31.000000000 +0100 +@@ -644,7 +644,7 @@ elf_symfile_read (struct objfile *objfil + /* If we are reinitializing, or if we have never loaded syms yet, + set table to empty. MAINLINE is cleared so that *_read_psymtab + functions do not all also re-initialize the psymbol table. */ +- if (mainline) ++ if (mainline == 1) + { + init_psymbol_list (objfile, 0); + mainline = 0; +Index: gdb/Makefile.in +=================================================================== +--- a/gdb/Makefile.in 2008-02-27 08:57:20.000000000 +0100 ++++ b/gdb/Makefile.in 2008-02-27 08:57:31.000000000 +0100 +@@ -1914,7 +1914,7 @@ amd64-tdep.o: amd64-tdep.c $(defs_h) $(a + $(dummy_frame_h) $(frame_h) $(frame_base_h) $(frame_unwind_h) \ + $(inferior_h) $(gdbcmd_h) $(gdbcore_h) $(objfiles_h) $(regcache_h) \ + $(regset_h) $(symfile_h) $(gdb_assert_h) $(amd64_tdep_h) \ +- $(i387_tdep_h) ++ $(i387_tdep_h) $(exceptions_h) + annotate.o: annotate.c $(defs_h) $(annotate_h) $(value_h) $(target_h) \ + $(gdbtypes_h) $(breakpoint_h) + arch-utils.o: arch-utils.c $(defs_h) $(arch_utils_h) $(buildsym_h) \ +Index: gdb/amd64-tdep.c +=================================================================== +--- a/gdb/amd64-tdep.c 2008-02-27 08:57:19.000000000 +0100 ++++ b/gdb/amd64-tdep.c 2008-02-27 08:57:31.000000000 +0100 +@@ -36,6 +36,7 @@ + #include "symfile.h" + #include "dwarf2-frame.h" + #include "gdb_assert.h" ++#include "exceptions.h" + + #include "amd64-tdep.h" + #include "i387-tdep.h" +@@ -731,16 +732,28 @@ amd64_alloc_frame_cache (void) + Any function that doesn't start with this sequence will be assumed + to have no prologue and thus no valid frame pointer in %rbp. */ + +-static CORE_ADDR +-amd64_analyze_prologue (CORE_ADDR pc, CORE_ADDR current_pc, +- struct amd64_frame_cache *cache) ++struct amd64_analyze_prologue_data ++ { ++ CORE_ADDR pc, current_pc; ++ struct amd64_frame_cache *cache; ++ CORE_ADDR retval; ++ }; ++ ++static int ++amd64_analyze_prologue_1 (void *data_pointer) + { ++ struct amd64_analyze_prologue_data *data = data_pointer; ++ CORE_ADDR pc = data->pc, current_pc = data->current_pc; ++ struct amd64_frame_cache *cache = data->cache; + static gdb_byte proto[3] = { 0x48, 0x89, 0xe5 }; /* movq %rsp, %rbp */ + gdb_byte buf[3]; + gdb_byte op; + + if (current_pc <= pc) +- return current_pc; ++ { ++ data->retval = current_pc; ++ return 1; ++ } + + op = read_memory_unsigned_integer (pc, 1); + +@@ -753,18 +766,57 @@ amd64_analyze_prologue (CORE_ADDR pc, CO + + /* If that's all, return now. */ + if (current_pc <= pc + 1) +- return current_pc; ++ { ++ data->retval = current_pc; ++ return 1; ++ } + + /* Check for `movq %rsp, %rbp'. */ + read_memory (pc + 1, buf, 3); + if (memcmp (buf, proto, 3) != 0) +- return pc + 1; ++ { ++ data->retval = pc + 1; ++ return 1; ++ } + + /* OK, we actually have a frame. */ + cache->frameless_p = 0; +- return pc + 4; ++ data->retval = pc + 4; ++ return 1; + } + ++ data->retval = pc; ++ return 1; ++} ++ ++/* Catch memory read errors and return just PC in such case. ++ It occurs very early on enable_break->new_symfile_objfile-> ++ ->breakpoint_re_set->decode_line_1->decode_variable_1-> ++ ->find_function_start_sal */ ++ ++static CORE_ADDR ++amd64_analyze_prologue (CORE_ADDR pc, CORE_ADDR current_pc, ++ struct amd64_frame_cache *cache) ++{ ++ int status; ++ struct amd64_analyze_prologue_data data; ++ struct ui_file *saved_gdb_stderr; ++ ++ /* Suppress error messages. */ ++ saved_gdb_stderr = gdb_stderr; ++ gdb_stderr = ui_file_new (); ++ ++ data.pc = pc; ++ data.current_pc = current_pc; ++ data.cache = cache; ++ status = catch_errors (amd64_analyze_prologue_1, &data, "", RETURN_MASK_ALL); ++ ++ /* Stop suppressing error messages. */ ++ ui_file_delete (gdb_stderr); ++ gdb_stderr = saved_gdb_stderr; ++ ++ if (status) ++ return data.retval; + return pc; + } + |