From 3a58abaf1ad4c3adaf17a0189f91596c7c73d3fc Mon Sep 17 00:00:00 2001 From: =?utf8?q?Arkadiusz=20Mi=C5=9Bkiewicz?= Date: Sun, 22 Mar 2009 23:28:33 +0000 Subject: [PATCH] - from fedora Changed files: gdb-6.3-attach-see-vdso-test.patch -> 1.1 gdb-6.3-bt-past-zero-20051201.patch -> 1.1 gdb-6.3-bz140532-ppc-unwinding-test.patch -> 1.1 gdb-6.3-bz202689-exec-from-pthread-test.patch -> 1.1 gdb-6.3-bz231832-obstack-2gb.patch -> 1.1 gdb-6.3-dtorfix-20050121.patch -> 1.1 gdb-6.3-focus-cmd-prev-test.patch -> 1.1 gdb-6.3-framepczero-20040927.patch -> 1.1 gdb-6.3-gcore-thread-20050204.patch -> 1.1 gdb-6.3-gstack-20050411.patch -> 1.1 gdb-6.3-gstack-without-path-20060414.patch -> 1.1 gdb-6.3-ia64-gcore-page0-20050421.patch -> 1.1 gdb-6.3-ia64-gcore-speedup-20050714.patch -> 1.1 gdb-6.3-ia64-info-frame-fix-20050725.patch -> 1.1 gdb-6.3-ia64-sigill-20051115.patch -> 1.1 gdb-6.3-ia64-sigtramp-fp-20050926.patch -> 1.1 gdb-6.3-ia64-sigtramp-frame-20050708.patch -> 1.1 gdb-6.3-inferior-notification-20050721.patch -> 1.1 gdb-6.3-inheritance-20050324.patch -> 1.1 gdb-6.3-inheritancetest-20050726.patch -> 1.1 gdb-6.3-large-core-20051206.patch -> 1.1 gdb-6.3-linespec-20041213.patch -> 1.1 gdb-6.3-mapping-zero-inode-test.patch -> 1.1 gdb-6.3-nonthreaded-wp-20050117.patch -> 1.1 gdb-6.3-pie-20050110.patch -> 1.1 gdb-6.3-ppc64displaysymbol-20041124.patch -> 1.1 gdb-6.3-ppc64syscall-20040622.patch -> 1.1 gdb-6.3-ppcdotsolib-20041022.patch -> 1.1 gdb-6.3-readnever-20050907.patch -> 1.1 gdb-6.3-removebp-20041130.patch -> 1.1 gdb-6.3-rh-dummykfail-20041202.patch -> 1.1 gdb-6.3-rh-testlibunwind-20041202.patch -> 1.1 gdb-6.3-rh-testlibunwind1fix-20041202.patch -> 1.1 gdb-6.3-rh-testversion-20041202.patch -> 1.1 gdb-6.3-security-errata-20050610.patch -> 1.1 gdb-6.3-sepcrc-20050402.patch -> 1.1 gdb-6.3-step-thread-exit-20050211-test.patch -> 1.1 gdb-6.3-terminal-fix-20050214.patch -> 1.1 gdb-6.3-test-dtorfix-20050121.patch -> 1.1 gdb-6.3-test-movedir-20050125.patch -> 1.1 gdb-6.3-test-pie-20050107.patch -> 1.1 gdb-6.3-test-self-20050110.patch -> 1.1 gdb-6.3-test-sepcrc-20050402.patch -> 1.1 gdb-6.3-threaded-watchpoints2-20050225.patch -> 1.1 gdb-6.3-watchpoint-cond-gone-test.patch -> 1.1 gdb-6.5-BEA-testsuite.patch -> 1.1 gdb-6.5-bz109921-DW_AT_decl_file-test.patch -> 1.1 gdb-6.5-bz181390-memory-address-width.patch -> 1.1 gdb-6.5-bz185337-resolve-tls-without-debuginfo-v2.patch -> 1.1 gdb-6.5-bz190810-gdbserver-arch-advice.patch -> 1.1 gdb-6.5-bz203661-emit-relocs.patch -> 1.1 gdb-6.5-bz216711-clone-is-outermost.patch -> 1.1 gdb-6.5-bz218379-ppc-solib-trampoline-fix.patch -> 1.1 gdb-6.5-bz218379-ppc-solib-trampoline-test.patch -> 1.1 gdb-6.5-bz218379-solib-trampoline-lookup-lock-fix.patch -> 1.1 gdb-6.5-bz243845-stale-testing-zombie-test.patch -> 1.1 gdb-6.5-dwarf-stack-overflow.patch -> 1.1 gdb-6.5-gcore-buffer-limit-test.patch -> 1.1 gdb-6.5-gcore-i386-on-amd64.patch -> 1.1 gdb-6.5-ia64-libunwind-leak-test.patch -> 1.1 gdb-6.5-last-address-space-byte-test.patch -> 1.1 gdb-6.5-missed-trap-on-step-test.patch -> 1.1 gdb-6.5-readline-long-line-crash-test.patch -> 1.1 gdb-6.5-readline-long-line-crash.patch -> 1.1 gdb-6.5-section-num-fixup-test.patch -> 1.1 gdb-6.5-sharedlibrary-path.patch -> 1.1 gdb-6.5-tls-of-separate-debuginfo.patch -> 1.1 gdb-6.6-buildid-locate-rpm.patch -> 1.1 gdb-6.6-buildid-locate.patch -> 1.1 gdb-6.6-bz225783-gdb-debuginfo-paths.patch -> 1.1 gdb-6.6-bz225783-prelink-path.patch -> 1.1 gdb-6.6-bz229517-gcore-without-terminal.patch -> 1.1 gdb-6.6-bz230000-power6-disassembly-test.patch -> 1.1 gdb-6.6-bz235197-fork-detach-info.patch -> 1.1 gdb-6.6-bz237572-ppc-atomic-sequence-test.patch -> 1.1 gdb-6.6-bz247354-leader-exit-fix.patch -> 1.1 gdb-6.6-bz247354-leader-exit-test.patch -> 1.1 gdb-6.6-gcore32-test.patch -> 1.1 gdb-6.6-multifork-debugreg.patch -> 1.1 gdb-6.6-readline-system.patch -> 1.1 gdb-6.6-scheduler_locking-step-is-default.patch -> 1.1 gdb-6.6-scheduler_locking-step-sw-watchpoints2.patch -> 1.1 gdb-6.6-step-thread-exit.patch -> 1.1 gdb-6.6-testsuite-timeouts.patch -> 1.1 gdb-6.6-threads-static-test.patch -> 1.1 gdb-6.7-bz426600-DW_TAG_interface_type-fix.patch -> 1.1 gdb-6.7-bz426600-DW_TAG_interface_type-test.patch -> 1.1 gdb-6.7-charsign-test.patch -> 1.1 gdb-6.7-kernel-headers-compat.patch -> 1.1 gdb-6.7-ppc-clobbered-registers-O2-test.patch -> 1.1 gdb-6.7-testsuite-stable-results.patch -> 1.1 gdb-6.8-attach-signalled-detach-stopped.patch -> 1.1 gdb-6.8-bz254229-gcore-prpsinfo.patch -> 1.1 gdb-6.8-bz436037-reg-no-longer-active.patch -> 1.1 gdb-6.8-bz442765-threaded-exec-test.patch -> 1.1 gdb-6.8-bz457187-largefile.patch -> 1.1 gdb-6.8-bz466901-backtrace-full-prelinked.patch -> 1.1 gdb-6.8-constant-watchpoints.patch -> 1.1 gdb-6.8-ctors-dtors-unique.patch -> 1.1 gdb-6.8-fortran-tag-constant.patch -> 1.1 gdb-6.8-gcc35998-ada-memory-trash.patch -> 1.1 gdb-6.8-glibc-headers-compat.patch -> 1.1 gdb-6.8-inlining-addon.patch -> 1.1 gdb-6.8-inlining-by-name.patch -> 1.1 gdb-6.8-inlining.patch -> 1.1 gdb-6.8-quit-never-aborts.patch -> 1.1 gdb-6.8-sparc64-silence-memcpy-check.patch -> 1.1 gdb-6.8-tui-singlebinary.patch -> 1.1 gdb-6.8-watchpoint-conditionals-test.patch -> 1.1 gdb-archer.patch -> 1.1 --- gdb-6.3-attach-see-vdso-test.patch | 110 + gdb-6.3-bt-past-zero-20051201.patch | 88 + gdb-6.3-bz140532-ppc-unwinding-test.patch | 317 + gdb-6.3-bz202689-exec-from-pthread-test.patch | 98 + gdb-6.3-bz231832-obstack-2gb.patch | 201 + gdb-6.3-dtorfix-20050121.patch | 52 + gdb-6.3-focus-cmd-prev-test.patch | 28 + gdb-6.3-framepczero-20040927.patch | 28 + gdb-6.3-gcore-thread-20050204.patch | 25 + gdb-6.3-gstack-20050411.patch | 115 + gdb-6.3-gstack-without-path-20060414.patch | 34 + gdb-6.3-ia64-gcore-page0-20050421.patch | 20 + gdb-6.3-ia64-gcore-speedup-20050714.patch | 126 + gdb-6.3-ia64-info-frame-fix-20050725.patch | 110 + gdb-6.3-ia64-sigill-20051115.patch | 116 + gdb-6.3-ia64-sigtramp-fp-20050926.patch | 163 + gdb-6.3-ia64-sigtramp-frame-20050708.patch | 158 + gdb-6.3-inferior-notification-20050721.patch | 322 + gdb-6.3-inheritance-20050324.patch | 26 + gdb-6.3-inheritancetest-20050726.patch | 153 + gdb-6.3-large-core-20051206.patch | 316 + gdb-6.3-linespec-20041213.patch | 464 + gdb-6.3-mapping-zero-inode-test.patch | 221 + gdb-6.3-nonthreaded-wp-20050117.patch | 119 + gdb-6.3-pie-20050110.patch | 1441 + gdb-6.3-ppc64displaysymbol-20041124.patch | 24 + gdb-6.3-ppc64syscall-20040622.patch | 110 + gdb-6.3-ppcdotsolib-20041022.patch | 31 + gdb-6.3-readnever-20050907.patch | 96 + gdb-6.3-removebp-20041130.patch | 29 + gdb-6.3-rh-dummykfail-20041202.patch | 22 + gdb-6.3-rh-testlibunwind-20041202.patch | 76 + gdb-6.3-rh-testlibunwind1fix-20041202.patch | 14 + gdb-6.3-rh-testversion-20041202.patch | 19 + gdb-6.3-security-errata-20050610.patch | 211 + gdb-6.3-sepcrc-20050402.patch | 82 + gdb-6.3-step-thread-exit-20050211-test.patch | 195 + gdb-6.3-terminal-fix-20050214.patch | 28 + gdb-6.3-test-dtorfix-20050121.patch | 263 + gdb-6.3-test-movedir-20050125.patch | 105 + gdb-6.3-test-pie-20050107.patch | 2121 + gdb-6.3-test-self-20050110.patch | 101 + gdb-6.3-test-sepcrc-20050402.patch | 55 + gdb-6.3-threaded-watchpoints2-20050225.patch | 250 + gdb-6.3-watchpoint-cond-gone-test.patch | 128 + gdb-6.5-BEA-testsuite.patch | 938 + gdb-6.5-bz109921-DW_AT_decl_file-test.patch | 120 + gdb-6.5-bz181390-memory-address-width.patch | 197 + ...337-resolve-tls-without-debuginfo-v2.patch | 261 + gdb-6.5-bz190810-gdbserver-arch-advice.patch | 29 + gdb-6.5-bz203661-emit-relocs.patch | 17 + gdb-6.5-bz216711-clone-is-outermost.patch | 278 + ....5-bz218379-ppc-solib-trampoline-fix.patch | 19 + ...5-bz218379-ppc-solib-trampoline-test.patch | 91 + ...379-solib-trampoline-lookup-lock-fix.patch | 21 + ...5-bz243845-stale-testing-zombie-test.patch | 86 + gdb-6.5-dwarf-stack-overflow.patch | 52 + gdb-6.5-gcore-buffer-limit-test.patch | 146 + gdb-6.5-gcore-i386-on-amd64.patch | 847 + gdb-6.5-ia64-libunwind-leak-test.patch | 127 + gdb-6.5-last-address-space-byte-test.patch | 56 + gdb-6.5-missed-trap-on-step-test.patch | 90 + gdb-6.5-readline-long-line-crash-test.patch | 136 + gdb-6.5-readline-long-line-crash.patch | 165 + gdb-6.5-section-num-fixup-test.patch | 111 + gdb-6.5-sharedlibrary-path.patch | 171 + gdb-6.5-tls-of-separate-debuginfo.patch | 24 + gdb-6.6-buildid-locate-rpm.patch | 1660 + gdb-6.6-buildid-locate.patch | 987 + gdb-6.6-bz225783-gdb-debuginfo-paths.patch | 33 + gdb-6.6-bz225783-prelink-path.patch | 27 + gdb-6.6-bz229517-gcore-without-terminal.patch | 191 + ...6.6-bz230000-power6-disassembly-test.patch | 83 + gdb-6.6-bz235197-fork-detach-info.patch | 128 + ....6-bz237572-ppc-atomic-sequence-test.patch | 270 + gdb-6.6-bz247354-leader-exit-fix.patch | 142 + gdb-6.6-bz247354-leader-exit-test.patch | 121 + gdb-6.6-gcore32-test.patch | 216 + gdb-6.6-multifork-debugreg.patch | 1337 + gdb-6.6-readline-system.patch | 116 + ....6-scheduler_locking-step-is-default.patch | 41 + ...heduler_locking-step-sw-watchpoints2.patch | 202 + gdb-6.6-step-thread-exit.patch | 61 + gdb-6.6-testsuite-timeouts.patch | 42 + gdb-6.6-threads-static-test.patch | 25 + ...7-bz426600-DW_TAG_interface_type-fix.patch | 41 + ...-bz426600-DW_TAG_interface_type-test.patch | 710 + gdb-6.7-charsign-test.patch | 125 + gdb-6.7-kernel-headers-compat.patch | 24 + gdb-6.7-ppc-clobbered-registers-O2-test.patch | 103 + gdb-6.7-testsuite-stable-results.patch | 208 + gdb-6.8-attach-signalled-detach-stopped.patch | 183 + gdb-6.8-bz254229-gcore-prpsinfo.patch | 351 + gdb-6.8-bz436037-reg-no-longer-active.patch | 24 + gdb-6.8-bz442765-threaded-exec-test.patch | 173 + gdb-6.8-bz457187-largefile.patch | 423 + ....8-bz466901-backtrace-full-prelinked.patch | 488 + gdb-6.8-constant-watchpoints.patch | 236 + gdb-6.8-ctors-dtors-unique.patch | 73 + gdb-6.8-fortran-tag-constant.patch | 76 + gdb-6.8-gcc35998-ada-memory-trash.patch | 18 + gdb-6.8-glibc-headers-compat.patch | 14 + gdb-6.8-inlining-addon.patch | 713 + gdb-6.8-inlining-by-name.patch | 104 + gdb-6.8-inlining.patch | 3268 ++ gdb-6.8-quit-never-aborts.patch | 72 + gdb-6.8-sparc64-silence-memcpy-check.patch | 11 + gdb-6.8-tui-singlebinary.patch | 24 + gdb-6.8-watchpoint-conditionals-test.patch | 78 + gdb-archer.patch | 40388 ++++++++++++++++ 110 files changed, 66403 insertions(+) create mode 100644 gdb-6.3-attach-see-vdso-test.patch create mode 100644 gdb-6.3-bt-past-zero-20051201.patch create mode 100644 gdb-6.3-bz140532-ppc-unwinding-test.patch create mode 100644 gdb-6.3-bz202689-exec-from-pthread-test.patch create mode 100644 gdb-6.3-bz231832-obstack-2gb.patch create mode 100644 gdb-6.3-dtorfix-20050121.patch create mode 100644 gdb-6.3-focus-cmd-prev-test.patch create mode 100644 gdb-6.3-framepczero-20040927.patch create mode 100644 gdb-6.3-gcore-thread-20050204.patch create mode 100644 gdb-6.3-gstack-20050411.patch create mode 100644 gdb-6.3-gstack-without-path-20060414.patch create mode 100644 gdb-6.3-ia64-gcore-page0-20050421.patch create mode 100644 gdb-6.3-ia64-gcore-speedup-20050714.patch create mode 100644 gdb-6.3-ia64-info-frame-fix-20050725.patch create mode 100644 gdb-6.3-ia64-sigill-20051115.patch create mode 100644 gdb-6.3-ia64-sigtramp-fp-20050926.patch create mode 100644 gdb-6.3-ia64-sigtramp-frame-20050708.patch create mode 100644 gdb-6.3-inferior-notification-20050721.patch create mode 100644 gdb-6.3-inheritance-20050324.patch create mode 100644 gdb-6.3-inheritancetest-20050726.patch create mode 100644 gdb-6.3-large-core-20051206.patch create mode 100644 gdb-6.3-linespec-20041213.patch create mode 100644 gdb-6.3-mapping-zero-inode-test.patch create mode 100644 gdb-6.3-nonthreaded-wp-20050117.patch create mode 100644 gdb-6.3-pie-20050110.patch create mode 100644 gdb-6.3-ppc64displaysymbol-20041124.patch create mode 100644 gdb-6.3-ppc64syscall-20040622.patch create mode 100644 gdb-6.3-ppcdotsolib-20041022.patch create mode 100644 gdb-6.3-readnever-20050907.patch create mode 100644 gdb-6.3-removebp-20041130.patch create mode 100644 gdb-6.3-rh-dummykfail-20041202.patch create mode 100644 gdb-6.3-rh-testlibunwind-20041202.patch create mode 100644 gdb-6.3-rh-testlibunwind1fix-20041202.patch create mode 100644 gdb-6.3-rh-testversion-20041202.patch create mode 100644 gdb-6.3-security-errata-20050610.patch create mode 100644 gdb-6.3-sepcrc-20050402.patch create mode 100644 gdb-6.3-step-thread-exit-20050211-test.patch create mode 100644 gdb-6.3-terminal-fix-20050214.patch create mode 100644 gdb-6.3-test-dtorfix-20050121.patch create mode 100644 gdb-6.3-test-movedir-20050125.patch create mode 100644 gdb-6.3-test-pie-20050107.patch create mode 100644 gdb-6.3-test-self-20050110.patch create mode 100644 gdb-6.3-test-sepcrc-20050402.patch create mode 100644 gdb-6.3-threaded-watchpoints2-20050225.patch create mode 100644 gdb-6.3-watchpoint-cond-gone-test.patch create mode 100644 gdb-6.5-BEA-testsuite.patch create mode 100644 gdb-6.5-bz109921-DW_AT_decl_file-test.patch create mode 100644 gdb-6.5-bz181390-memory-address-width.patch create mode 100644 gdb-6.5-bz185337-resolve-tls-without-debuginfo-v2.patch create mode 100644 gdb-6.5-bz190810-gdbserver-arch-advice.patch create mode 100644 gdb-6.5-bz203661-emit-relocs.patch create mode 100644 gdb-6.5-bz216711-clone-is-outermost.patch create mode 100644 gdb-6.5-bz218379-ppc-solib-trampoline-fix.patch create mode 100644 gdb-6.5-bz218379-ppc-solib-trampoline-test.patch create mode 100644 gdb-6.5-bz218379-solib-trampoline-lookup-lock-fix.patch create mode 100644 gdb-6.5-bz243845-stale-testing-zombie-test.patch create mode 100644 gdb-6.5-dwarf-stack-overflow.patch create mode 100644 gdb-6.5-gcore-buffer-limit-test.patch create mode 100644 gdb-6.5-gcore-i386-on-amd64.patch create mode 100644 gdb-6.5-ia64-libunwind-leak-test.patch create mode 100644 gdb-6.5-last-address-space-byte-test.patch create mode 100644 gdb-6.5-missed-trap-on-step-test.patch create mode 100644 gdb-6.5-readline-long-line-crash-test.patch create mode 100644 gdb-6.5-readline-long-line-crash.patch create mode 100644 gdb-6.5-section-num-fixup-test.patch create mode 100644 gdb-6.5-sharedlibrary-path.patch create mode 100644 gdb-6.5-tls-of-separate-debuginfo.patch create mode 100644 gdb-6.6-buildid-locate-rpm.patch create mode 100644 gdb-6.6-buildid-locate.patch create mode 100644 gdb-6.6-bz225783-gdb-debuginfo-paths.patch create mode 100644 gdb-6.6-bz225783-prelink-path.patch create mode 100644 gdb-6.6-bz229517-gcore-without-terminal.patch create mode 100644 gdb-6.6-bz230000-power6-disassembly-test.patch create mode 100644 gdb-6.6-bz235197-fork-detach-info.patch create mode 100644 gdb-6.6-bz237572-ppc-atomic-sequence-test.patch create mode 100644 gdb-6.6-bz247354-leader-exit-fix.patch create mode 100644 gdb-6.6-bz247354-leader-exit-test.patch create mode 100644 gdb-6.6-gcore32-test.patch create mode 100644 gdb-6.6-multifork-debugreg.patch create mode 100644 gdb-6.6-readline-system.patch create mode 100644 gdb-6.6-scheduler_locking-step-is-default.patch create mode 100644 gdb-6.6-scheduler_locking-step-sw-watchpoints2.patch create mode 100644 gdb-6.6-step-thread-exit.patch create mode 100644 gdb-6.6-testsuite-timeouts.patch create mode 100644 gdb-6.6-threads-static-test.patch create mode 100644 gdb-6.7-bz426600-DW_TAG_interface_type-fix.patch create mode 100644 gdb-6.7-bz426600-DW_TAG_interface_type-test.patch create mode 100644 gdb-6.7-charsign-test.patch create mode 100644 gdb-6.7-kernel-headers-compat.patch create mode 100644 gdb-6.7-ppc-clobbered-registers-O2-test.patch create mode 100644 gdb-6.7-testsuite-stable-results.patch create mode 100644 gdb-6.8-attach-signalled-detach-stopped.patch create mode 100644 gdb-6.8-bz254229-gcore-prpsinfo.patch create mode 100644 gdb-6.8-bz436037-reg-no-longer-active.patch create mode 100644 gdb-6.8-bz442765-threaded-exec-test.patch create mode 100644 gdb-6.8-bz457187-largefile.patch create mode 100644 gdb-6.8-bz466901-backtrace-full-prelinked.patch create mode 100644 gdb-6.8-constant-watchpoints.patch create mode 100644 gdb-6.8-ctors-dtors-unique.patch create mode 100644 gdb-6.8-fortran-tag-constant.patch create mode 100644 gdb-6.8-gcc35998-ada-memory-trash.patch create mode 100644 gdb-6.8-glibc-headers-compat.patch create mode 100644 gdb-6.8-inlining-addon.patch create mode 100644 gdb-6.8-inlining-by-name.patch create mode 100644 gdb-6.8-inlining.patch create mode 100644 gdb-6.8-quit-never-aborts.patch create mode 100644 gdb-6.8-sparc64-silence-memcpy-check.patch create mode 100644 gdb-6.8-tui-singlebinary.patch create mode 100644 gdb-6.8-watchpoint-conditionals-test.patch create mode 100644 gdb-archer.patch diff --git a/gdb-6.3-attach-see-vdso-test.patch b/gdb-6.3-attach-see-vdso-test.patch new file mode 100644 index 0000000..58a15db --- /dev/null +++ b/gdb-6.3-attach-see-vdso-test.patch @@ -0,0 +1,110 @@ +--- /dev/null 1 Jan 1970 00:00:00 -0000 ++++ ./gdb/testsuite/gdb.base/attach-see-vdso.c 6 Jul 2007 14:14:44 -0000 +@@ -0,0 +1,25 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2007 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ ++ ++#include ++ ++int main () ++{ ++ pause (); ++ return 1; ++} +--- /dev/null 1 Jan 1970 00:00:00 -0000 ++++ ./gdb/testsuite/gdb.base/attach-see-vdso.exp 6 Jul 2007 14:14:44 -0000 +@@ -0,0 +1,79 @@ ++# Copyright 2007 ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++# This file was created by Jan Kratochvil . ++ ++if $tracelevel then { ++ strace $tracelevel ++} ++ ++set prms_id 0 ++set bug_id 0 ++ ++# This test only works on Linux ++if { ![istarget "*-*-linux-gnu*"] } { ++ return 0 ++} ++ ++set testfile "attach-see-vdso" ++set srcfile ${testfile}.c ++set binfile ${objdir}/${subdir}/${testfile} ++set escapedbinfile [string_to_regexp ${objdir}/${subdir}/${testfile}] ++ ++# The kernel VDSO is used for the syscalls returns only on i386 (not x86_64). ++# ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug additional_flags=-m32}] != "" } { ++ gdb_suppress_entire_file "Testcase nonthraded compile failed, so all tests in this file will automatically fail." ++} ++ ++if [get_compiler_info ${binfile}] { ++ return -1 ++} ++ ++# Start the program running and then wait for a bit, to be sure ++# that it can be attached to. ++ ++set testpid [eval exec $binfile &] ++ ++# Avoid some race: ++sleep 2 ++ ++# Start with clean gdb ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++# Never call: gdb_load ${binfile} ++# as the former problem would not reproduce otherwise. ++ ++set test "attach" ++gdb_test_multiple "attach $testpid" "$test" { ++ -re "Attaching to process $testpid\r?\n.*$gdb_prompt $" { ++ pass "$test" ++ } ++} ++ ++gdb_test "bt" "#0 *0x\[0-9a-f\]* in \[^?\].*" "backtrace decodes VDSO" ++ ++# Exit and detach the process. ++ ++gdb_exit ++ ++# Make sure we don't leave a process around to confuse ++# the next test run (and prevent the compile by keeping ++# the text file busy), in case the "set should_exit" didn't ++# work. ++ ++remote_exec build "kill -9 ${testpid}" diff --git a/gdb-6.3-bt-past-zero-20051201.patch b/gdb-6.3-bt-past-zero-20051201.patch new file mode 100644 index 0000000..4d6e2d8 --- /dev/null +++ b/gdb-6.3-bt-past-zero-20051201.patch @@ -0,0 +1,88 @@ +2005-12-01 Jeff Johnston + + * frame.c (backtrace_past_zero_pc): New static variable. + (get_prev_frame): Don't return NULL for zero pc value if + backtrace past-zero-frame option is turned on. + (_initialize_frame): Initialize new command to allow backtracing + past a zero pc value (set backtrace past-zero-pc). + +testsuite/gdb.base: +2005-12-01 Jeff Johnston + + * setshow.exp: Add testing of "set backtrace past-zero-pc" option. + +2007-10-15 Jan Kratochvil + + Port to GDB-6.7. + +Index: gdb-6.7/gdb/testsuite/gdb.base/setshow.exp +=================================================================== +--- gdb-6.7.orig/gdb/testsuite/gdb.base/setshow.exp 2007-08-23 20:14:17.000000000 +0200 ++++ gdb-6.7/gdb/testsuite/gdb.base/setshow.exp 2007-10-15 21:34:52.000000000 +0200 +@@ -106,6 +106,16 @@ if { ![target_info exists use_gdb_stub] + delete_breakpoints + gdb_test "run" "Starting program:.*foo bar blup baz bubble.*" "passing args" + } ++#test show backtrace past-zero-pc ++gdb_test "show backtrace past-zero-pc" "Whether backtraces should continue past a zero pc value is off." "default show backtrace past-zero-pc (off)" ++#test set backtrace past-zero-pc on ++gdb_test "set backtrace past-zero-pc on" "" "set backtrace past-zero-pc on" ++#test show backtrace past-zero-pc ++gdb_test "show backtrace past-zero-pc" "Whether backtraces should continue past a zero pc value is on." "show backtrace past-zero-pc (on)" ++#test set backtrace past-zero-pc off ++gdb_test "set backtrace past-zero-pc off" "" "set backtrace past-zero-pc off" ++#test show backtrace past-zero-pc ++gdb_test "show backtrace past-zero-pc" "Whether backtraces should continue past a zero pc value is off." "show backtrace past-zero-pc (off)" + #test set check range on + gdb_test "set check range on" "" "set check range on" + #test show check range on +Index: gdb-6.7/gdb/frame.c +=================================================================== +--- gdb-6.7.orig/gdb/frame.c 2007-10-12 22:35:58.000000000 +0200 ++++ gdb-6.7/gdb/frame.c 2007-10-15 21:34:52.000000000 +0200 +@@ -133,6 +133,16 @@ Whether backtraces should continue past + value); + } + ++static int backtrace_past_zero_pc; ++static void ++show_backtrace_past_zero_pc (struct ui_file *file, int from_tty, ++ struct cmd_list_element *c, const char *value) ++{ ++ fprintf_filtered (file, _("\ ++Whether backtraces should continue past a zero pc value is %s.\n"), ++ value); ++} ++ + static int backtrace_past_entry; + static void + show_backtrace_past_entry (struct ui_file *file, int from_tty, +@@ -1483,9 +1493,7 @@ get_prev_frame (struct frame_info *this_ + } + + if (this_frame->level > 0 +-#if 0 +- && backtrace_past_zero_pc +-#endif ++ && !backtrace_past_zero_pc + && get_frame_type (this_frame) == NORMAL_FRAME + && get_frame_type (get_next_frame (this_frame)) == NORMAL_FRAME + && get_frame_pc (this_frame) == 0) +@@ -1850,6 +1858,17 @@ the rest of the stack trace."), + &set_backtrace_cmdlist, + &show_backtrace_cmdlist); + ++ add_setshow_boolean_cmd ("past-zero-pc", class_obscure, ++ &backtrace_past_zero_pc, _("\ ++Set whether backtraces should continue past a zero pc value."), _("\ ++Show whether backtraces should continue past a zero pc value."), _("\ ++Normally GDB stops backtracing when it finds a zero pc.\n\ ++Set this variable if you need to see the rest of the stack trace."), ++ NULL, ++ show_backtrace_past_zero_pc, ++ &set_backtrace_cmdlist, ++ &show_backtrace_cmdlist); ++ + add_setshow_integer_cmd ("limit", class_obscure, + &backtrace_limit, _("\ + Set an upper bound on the number of backtrace levels."), _("\ diff --git a/gdb-6.3-bz140532-ppc-unwinding-test.patch b/gdb-6.3-bz140532-ppc-unwinding-test.patch new file mode 100644 index 0000000..d325ee3 --- /dev/null +++ b/gdb-6.3-bz140532-ppc-unwinding-test.patch @@ -0,0 +1,317 @@ +diff -u -ruNp gdb-6.3-unpatched/gdb/testsuite/gdb.arch/powerpc-bcl-prologue-asm32.S gdb-6.3/gdb/testsuite/gdb.arch/powerpc-bcl-prologue-asm32.S +--- gdb-6.3-unpatched/gdb/testsuite/gdb.arch/powerpc-bcl-prologue-asm32.S 1969-12-31 19:00:00.000000000 -0500 ++++ gdb-6.3/gdb/testsuite/gdb.arch/powerpc-bcl-prologue-asm32.S 2007-08-02 13:23:10.000000000 -0400 +@@ -0,0 +1,78 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2007 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ ++ ++ .section ".text" ++ .align 2 ++ .globl func0 ++ .type func0, @function ++func0: ++ stwu 1,-16(1) ++ mflr 0 ++ stw 31,12(1) ++ stw 0,20(1) ++ mr 31,1 ++ bl abort ++ .size func0, .-func0 ++ .align 2 ++ .globl func1 ++ .type func1, @function ++func1: ++ stwu 1,-16(1) ++ mflr 0 ++/* 20 = BO = branch always ++ 31 = BI = CR bit (ignored) */ ++ bcl 20,31,.Lpie ++.Lpie: stw 31,12(1) ++ stw 0,20(1) ++ mr 31,1 ++ bl func0 ++ mr 0,3 ++ lis 9,var@ha ++ lwz 9,var@l(9) ++ add 0,0,9 ++ mr 3,0 ++ lwz 11,0(1) ++ lwz 0,4(11) ++ mtlr 0 ++ lwz 31,-4(11) ++ mr 1,11 ++ blr ++ .size func1, .-func1 ++ .section .note.GNU-stack,"",@progbits ++ .ident "GCC: (GNU) 3.4.6 20060404 (Red Hat 3.4.6-8)" ++ ++/* Original source file: ++ ++#include ++ ++extern volatile int var; ++ ++int func0 (void) __attribute__((__noinline__)); ++int func0 (void) ++{ ++ abort (); ++ return var; ++} ++ ++int func1 (void) __attribute__((__noinline__)); ++int func1 (void) ++{ ++ return func0 () + var; ++} ++ ++*/ +diff -u -ruNp gdb-6.3-unpatched/gdb/testsuite/gdb.arch/powerpc-bcl-prologue-asm64.S gdb-6.3/gdb/testsuite/gdb.arch/powerpc-bcl-prologue-asm64.S +--- gdb-6.3-unpatched/gdb/testsuite/gdb.arch/powerpc-bcl-prologue-asm64.S 1969-12-31 19:00:00.000000000 -0500 ++++ gdb-6.3/gdb/testsuite/gdb.arch/powerpc-bcl-prologue-asm64.S 2007-08-02 14:28:56.000000000 -0400 +@@ -0,0 +1,98 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2007 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ ++ ++ .section ".toc","aw" ++ .section ".text" ++ .align 2 ++ .globl func0 ++ .section ".opd","aw" ++ .align 3 ++func0: ++ .quad .L.func0,.TOC.@tocbase ++ .previous ++ .type func0, @function ++.L.func0: ++ mflr 0 ++ std 31,-8(1) ++ std 0,16(1) ++ stdu 1,-128(1) ++ mr 31,1 ++ bl abort ++ nop ++ .long 0 ++ .byte 0,0,0,1,128,1,0,1 ++ .size func0,.-.L.func0 ++ .section ".toc","aw" ++.LC1: ++ .tc var[TC],var ++ .section ".text" ++ .align 2 ++ .globl func1 ++ .section ".opd","aw" ++ .align 3 ++func1: ++ .quad .L.func1,.TOC.@tocbase ++ .previous ++ .type func1, @function ++.L.func1: ++ mflr 0 ++/* 20 = BO = branch always ++ 31 = BI = CR bit (ignored) */ ++ bcl 20,31,.Lpie ++.Lpie: std 31,-8(1) ++ std 0,16(1) ++ stdu 1,-128(1) ++ mr 31,1 ++ bl func0 ++ mr 11,3 ++ ld 9,.LC1@toc(2) ++ lwz 0,0(9) ++ add 0,11,0 ++ extsw 0,0 ++ mr 3,0 ++ ld 1,0(1) ++ ld 0,16(1) ++ mtlr 0 ++ ld 31,-8(1) ++ blr ++ .long 0 ++ .byte 0,0,0,1,128,1,0,1 ++ .size func1,.-.L.func1 ++ .section .note.GNU-stack,"",@progbits ++ .ident "GCC: (GNU) 3.4.6 20060404 (Red Hat 3.4.6-8)" ++ ++/* Original source file: ++ ++#include ++ ++extern volatile int var; ++ ++int func0 (void) __attribute__((__noinline__)); ++int func0 (void) ++{ ++ abort (); ++ return var; ++} ++ ++int func1 (void) __attribute__((__noinline__)); ++int func1 (void) ++{ ++ return func0 () + var; ++} ++ ++*/ +diff -u -ruNp gdb-6.3-unpatched/gdb/testsuite/gdb.arch/powerpc-bcl-prologue.c gdb-6.3/gdb/testsuite/gdb.arch/powerpc-bcl-prologue.c +--- gdb-6.3-unpatched/gdb/testsuite/gdb.arch/powerpc-bcl-prologue.c 1969-12-31 19:00:00.000000000 -0500 ++++ gdb-6.3/gdb/testsuite/gdb.arch/powerpc-bcl-prologue.c 2007-08-02 13:25:10.000000000 -0400 +@@ -0,0 +1,29 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2007 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ ++ ++/* Force `-fpie' double jump bl->blrl. */ ++/* No longer used. */ ++volatile int var; ++ ++extern int func1 (void); ++ ++int main (void) ++{ ++ func1 (); ++ return 0; ++} +diff -u -ruNp gdb-6.3-unpatched/gdb/testsuite/gdb.arch/powerpc-bcl-prologue.exp gdb-6.3/gdb/testsuite/gdb.arch/powerpc-bcl-prologue.exp +--- gdb-6.3-unpatched/gdb/testsuite/gdb.arch/powerpc-bcl-prologue.exp 1969-12-31 19:00:00.000000000 -0500 ++++ gdb-6.3/gdb/testsuite/gdb.arch/powerpc-bcl-prologue.exp 2007-08-02 14:21:29.000000000 -0400 +@@ -0,0 +1,79 @@ ++# Copyright 2006, 2007 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++# Test unwinding fixes of the PPC platform, specifically on the coping with BCL ++# jump of the PIE code. ++ ++if $tracelevel then { ++ strace $tracelevel ++} ++ ++set prms_id 0 ++set bug_id 0 ++ ++if ![istarget "powerpc*-*-linux*"] then { ++ verbose "Skipping powerpc-linux prologue tests." ++ return ++} ++ ++set testfile "powerpc-bcl-prologue" ++set srcfile1 ${testfile}.c ++set flags "debug" ++if [istarget "powerpc-*"] then { ++ set srcfile2 ${testfile}-asm32.S ++ set flags "$flags additional_flags=-m32" ++} elseif [istarget "powerpc64-*"] then { ++ set srcfile2 ${testfile}-asm64.S ++ set flags "$flags additional_flags=-m64" ++} else { ++ fail "powerpc arch test" ++ return ++} ++set objfile2 ${objdir}/${subdir}/${testfile}-asm.o ++set binfile ${objdir}/${subdir}/${testfile} ++ ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile1} ${srcdir}/${subdir}/${srcfile2}" ${binfile} executable $flags] != ""} { ++ return -1 ++} ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++# We should stop in abort(3). ++ ++gdb_run_cmd ++ ++gdb_test_multiple {} "continue to abort()" { ++ -re ".*Program received signal SIGABRT,.*$gdb_prompt $" { ++ pass "continue to abort()" ++ } ++} ++ ++# Check backtrace: ++# #3 0x0804835f in func0 () ++# #4 0x0804836a in func1 () ++# #5 0x0804838c in main () ++# (gdb) ++# `\\.?' prefixes are needed for ppc64 without `debug' (another bug). ++ ++set test "matching unwind" ++gdb_test_multiple "backtrace" $test { ++ -re "\r\n#\[0-9\]\[^\r\n\]* in \\.?func0 \\(\[^\r\n\]*\r\n#\[0-9\]\[^\r\n\]* in \\.?func1 \\(\[^\r\n\]*\r\n#\[0-9\]\[^\r\n\]* in \\.?main \\(\[^\r\n\]*\r\n$gdb_prompt $" { ++ pass $test ++ } ++} + +Fixup the testcase for ppc64 biarch GDB. + +--- ./gdb/testsuite/gdb.arch/powerpc-prologue.exp 2008-01-13 13:32:19.000000000 +0100 ++++ ./gdb/testsuite/gdb.arch/powerpc-prologue.exp 2008-01-02 00:04:10.000000000 +0100 +@@ -17,8 +17,9 @@ + # Test PowerPC prologue analyzer. + + # Do not run on AIX (where we won't be able to build the tests without +-# some surgery) or on PowerPC64 (ditto, dot symbols). +-if {[istarget *-*-aix*] || ![istarget "powerpc-*-*"]} then { ++# some surgery). PowerPC64 target would break due to dot symbols but we build ++# there PowerPC32 inferior. ++if {[istarget *-*-aix*] || ![istarget "powerpc*-*-*"]} then { + verbose "Skipping PowerPC prologue tests." + return + } diff --git a/gdb-6.3-bz202689-exec-from-pthread-test.patch b/gdb-6.3-bz202689-exec-from-pthread-test.patch new file mode 100644 index 0000000..1d9c61b --- /dev/null +++ b/gdb-6.3-bz202689-exec-from-pthread-test.patch @@ -0,0 +1,98 @@ +2007-01-17 Jan Kratochvil + + * gdb.threads/threaded-exec.exp, gdb.threads/threaded-exec.c: New files. + + +--- /dev/null 1 Jan 1970 00:00:00 -0000 ++++ ./gdb/testsuite/gdb.threads/threaded-exec.c 17 Jan 2007 23:10:22 -0000 +@@ -0,0 +1,46 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2007 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place - Suite 330, ++ Boston, MA 02111-1307, USA. */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++ ++static void * ++threader (void *arg) ++{ ++ return NULL; ++} ++ ++int ++main (void) ++{ ++ pthread_t t1; ++ int i; ++ ++ i = pthread_create (&t1, NULL, threader, (void *) NULL); ++ assert (i == 0); ++ i = pthread_join (t1, NULL); ++ assert (i == 0); ++ ++ execl ("/bin/true", "/bin/true", NULL); ++ abort (); ++} +--- /dev/null 1 Jan 1970 00:00:00 -0000 ++++ ./gdb/testsuite/gdb.threads/threaded-exec.exp 17 Jan 2007 23:10:22 -0000 +@@ -0,0 +1,41 @@ ++# threaded-exec.exp -- Check reset of the tracked threads on exec*(2) ++# Copyright (C) 2007 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ ++ ++# Please email any bugs, comments, and/or additions to this file to: ++# bug-gdb@prep.ai.mit.edu ++ ++set testfile threaded-exec ++set srcfile ${testfile}.c ++set binfile ${objdir}/${subdir}/${testfile} ++ ++if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable []] != "" } { ++ return -1 ++} ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++ ++gdb_load ${binfile} ++ ++gdb_run_cmd ++ ++gdb_test_multiple {} "Program exited" { ++ -re "\r\nProgram exited normally.\r\n$gdb_prompt $" { ++ pass "Program exited" ++ } ++} diff --git a/gdb-6.3-bz231832-obstack-2gb.patch b/gdb-6.3-bz231832-obstack-2gb.patch new file mode 100644 index 0000000..47bd68b --- /dev/null +++ b/gdb-6.3-bz231832-obstack-2gb.patch @@ -0,0 +1,201 @@ +https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=231832 + + +Index: gdb-6.8/gdb/symmisc.c +=================================================================== +--- gdb-6.8.orig/gdb/symmisc.c 2008-03-17 16:06:24.000000000 +0100 ++++ gdb-6.8/gdb/symmisc.c 2008-07-14 10:27:50.000000000 +0200 +@@ -230,8 +230,8 @@ print_objfile_statistics (void) + if (OBJSTAT (objfile, sz_strtab) > 0) + printf_filtered (_(" Space used by a.out string tables: %d\n"), + OBJSTAT (objfile, sz_strtab)); +- printf_filtered (_(" Total memory used for objfile obstack: %d\n"), +- obstack_memory_used (&objfile->objfile_obstack)); ++ printf_filtered (_(" Total memory used for objfile obstack: %ld\n"), ++ (long) obstack_memory_used (&objfile->objfile_obstack)); + printf_filtered (_(" Total memory used for psymbol cache: %d\n"), + bcache_memory_used (objfile->psymbol_cache)); + printf_filtered (_(" Total memory used for macro cache: %d\n"), +Index: gdb-6.8/include/obstack.h +=================================================================== +--- gdb-6.8.orig/include/obstack.h 2005-05-10 12:21:08.000000000 +0200 ++++ gdb-6.8/include/obstack.h 2008-07-14 10:27:50.000000000 +0200 +@@ -188,31 +188,31 @@ struct obstack /* control current objec + + /* Declare the external functions we use; they are in obstack.c. */ + +-extern void _obstack_newchunk (struct obstack *, int); ++extern void _obstack_newchunk (struct obstack *, PTR_INT_TYPE); + extern void _obstack_free (struct obstack *, void *); +-extern int _obstack_begin (struct obstack *, int, int, ++extern int _obstack_begin (struct obstack *, PTR_INT_TYPE, int, + void *(*) (long), void (*) (void *)); +-extern int _obstack_begin_1 (struct obstack *, int, int, ++extern int _obstack_begin_1 (struct obstack *, PTR_INT_TYPE, int, + void *(*) (void *, long), + void (*) (void *, void *), void *); +-extern int _obstack_memory_used (struct obstack *); ++extern PTR_INT_TYPE _obstack_memory_used (struct obstack *); + + /* Do the function-declarations after the structs + but before defining the macros. */ + + void obstack_init (struct obstack *obstack); + +-void * obstack_alloc (struct obstack *obstack, int size); ++void * obstack_alloc (struct obstack *obstack, PTR_INT_TYPE size); + +-void * obstack_copy (struct obstack *obstack, void *address, int size); +-void * obstack_copy0 (struct obstack *obstack, void *address, int size); ++void * obstack_copy (struct obstack *obstack, void *address, PTR_INT_TYPE size); ++void * obstack_copy0 (struct obstack *obstack, void *address, PTR_INT_TYPE size); + + void obstack_free (struct obstack *obstack, void *block); + +-void obstack_blank (struct obstack *obstack, int size); ++void obstack_blank (struct obstack *obstack, PTR_INT_TYPE size); + +-void obstack_grow (struct obstack *obstack, void *data, int size); +-void obstack_grow0 (struct obstack *obstack, void *data, int size); ++void obstack_grow (struct obstack *obstack, void *data, PTR_INT_TYPE size); ++void obstack_grow0 (struct obstack *obstack, void *data, PTR_INT_TYPE size); + + void obstack_1grow (struct obstack *obstack, int data_char); + void obstack_ptr_grow (struct obstack *obstack, void *data); +@@ -220,20 +220,20 @@ void obstack_int_grow (struct obstack *o + + void * obstack_finish (struct obstack *obstack); + +-int obstack_object_size (struct obstack *obstack); ++PTR_INT_TYPE obstack_object_size (struct obstack *obstack); + +-int obstack_room (struct obstack *obstack); +-void obstack_make_room (struct obstack *obstack, int size); ++PTR_INT_TYPE obstack_room (struct obstack *obstack); ++void obstack_make_room (struct obstack *obstack, PTR_INT_TYPE size); + void obstack_1grow_fast (struct obstack *obstack, int data_char); + void obstack_ptr_grow_fast (struct obstack *obstack, void *data); + void obstack_int_grow_fast (struct obstack *obstack, int data); +-void obstack_blank_fast (struct obstack *obstack, int size); ++void obstack_blank_fast (struct obstack *obstack, PTR_INT_TYPE size); + + void * obstack_base (struct obstack *obstack); + void * obstack_next_free (struct obstack *obstack); + int obstack_alignment_mask (struct obstack *obstack); +-int obstack_chunk_size (struct obstack *obstack); +-int obstack_memory_used (struct obstack *obstack); ++size_t obstack_chunk_size (struct obstack *obstack); ++size_t obstack_memory_used (struct obstack *obstack); + + /* Error handler called when `obstack_chunk_alloc' failed to allocate + more memory. This can be set to a user defined function. The +@@ -318,7 +318,7 @@ extern int obstack_exit_failure; + # define obstack_make_room(OBSTACK,length) \ + __extension__ \ + ({ struct obstack *__o = (OBSTACK); \ +- int __len = (length); \ ++ PTR_INT_TYPE __len = (length); \ + if (__o->chunk_limit - __o->next_free < __len) \ + _obstack_newchunk (__o, __len); \ + (void) 0; }) +@@ -331,7 +331,7 @@ __extension__ \ + # define obstack_grow(OBSTACK,where,length) \ + __extension__ \ + ({ struct obstack *__o = (OBSTACK); \ +- int __len = (length); \ ++ PTR_INT_TYPE __len = (length); \ + if (__o->next_free + __len > __o->chunk_limit) \ + _obstack_newchunk (__o, __len); \ + _obstack_memcpy (__o->next_free, (where), __len); \ +@@ -341,7 +341,7 @@ __extension__ \ + # define obstack_grow0(OBSTACK,where,length) \ + __extension__ \ + ({ struct obstack *__o = (OBSTACK); \ +- int __len = (length); \ ++ PTR_INT_TYPE __len = (length); \ + if (__o->next_free + __len + 1 > __o->chunk_limit) \ + _obstack_newchunk (__o, __len + 1); \ + _obstack_memcpy (__o->next_free, (where), __len); \ +@@ -392,7 +392,7 @@ __extension__ \ + # define obstack_blank(OBSTACK,length) \ + __extension__ \ + ({ struct obstack *__o = (OBSTACK); \ +- int __len = (length); \ ++ PTR_INT_TYPE __len = (length); \ + if (__o->chunk_limit - __o->next_free < __len) \ + _obstack_newchunk (__o, __len); \ + obstack_blank_fast (__o, __len); \ +@@ -532,7 +532,7 @@ __extension__ \ + # define obstack_free(h,obj) \ + ( (h)->temp = (char *) (obj) - (char *) (h)->chunk, \ + (((h)->temp > 0 && (h)->temp < (h)->chunk_limit - (char *) (h)->chunk)\ +- ? (int) ((h)->next_free = (h)->object_base \ ++ ? (PTR_INT_TYPE) ((h)->next_free = (h)->object_base \ + = (h)->temp + (char *) (h)->chunk) \ + : (((obstack_free) ((h), (h)->temp + (char *) (h)->chunk), 0), 0))) + +Index: gdb-6.8/libiberty/obstack.c +=================================================================== +--- gdb-6.8.orig/libiberty/obstack.c 2005-05-10 17:33:33.000000000 +0200 ++++ gdb-6.8/libiberty/obstack.c 2008-07-14 10:27:50.000000000 +0200 +@@ -44,9 +44,11 @@ + #if !defined (_LIBC) && defined (__GNU_LIBRARY__) && __GNU_LIBRARY__ > 1 + #include + #if _GNU_OBSTACK_INTERFACE_VERSION == OBSTACK_INTERFACE_VERSION ++#if 0 /* 64-bit obstack is not compatible with any glibc implementation. */ + #define ELIDE_CODE + #endif + #endif ++#endif + + + #ifndef ELIDE_CODE +@@ -139,7 +141,7 @@ struct obstack *_obstack; + free up some memory, then call this again. */ + + int +-_obstack_begin (struct obstack *h, int size, int alignment, ++_obstack_begin (struct obstack *h, PTR_INT_TYPE size, int alignment, + POINTER (*chunkfun) (long), void (*freefun) (void *)) + { + register struct _obstack_chunk *chunk; /* points to new chunk */ +@@ -183,7 +185,7 @@ _obstack_begin (struct obstack *h, int s + } + + int +-_obstack_begin_1 (struct obstack *h, int size, int alignment, ++_obstack_begin_1 (struct obstack *h, PTR_INT_TYPE size, int alignment, + POINTER (*chunkfun) (POINTER, long), + void (*freefun) (POINTER, POINTER), POINTER arg) + { +@@ -235,7 +237,7 @@ _obstack_begin_1 (struct obstack *h, int + to the beginning of the new one. */ + + void +-_obstack_newchunk (struct obstack *h, int length) ++_obstack_newchunk (struct obstack *h, PTR_INT_TYPE length) + { + register struct _obstack_chunk *old_chunk = h->chunk; + register struct _obstack_chunk *new_chunk; +@@ -388,11 +390,11 @@ obstack_free (struct obstack *h, POINTER + abort (); + } + +-int ++PTR_INT_TYPE + _obstack_memory_used (struct obstack *h) + { + register struct _obstack_chunk* lp; +- register int nbytes = 0; ++ register PTR_INT_TYPE nbytes = 0; + + for (lp = h->chunk; lp != 0; lp = lp->prev) + { +@@ -421,6 +423,7 @@ print_and_abort (void) + } + + #if 0 ++/* These functions are now broken for 64-bit obstack! */ + /* These are now turned off because the applications do not use it + and it uses bcopy via obstack_grow, which causes trouble on sysV. */ + diff --git a/gdb-6.3-dtorfix-20050121.patch b/gdb-6.3-dtorfix-20050121.patch new file mode 100644 index 0000000..55cd23e --- /dev/null +++ b/gdb-6.3-dtorfix-20050121.patch @@ -0,0 +1,52 @@ +2005-01-21 Jeff Johnston + + * linespec.c (collect_methods): Don't do special processing for + destructors as this will be handled in find_methods. + (find_methods): Fix ctor check to also check for dtor. + +2007-10-14 Jan Kratochvil + + Port to GDB-6.7. + +Index: gdb-6.7/gdb/linespec.c +=================================================================== +--- gdb-6.7.orig/gdb/linespec.c 2007-10-13 05:26:33.000000000 +0200 ++++ gdb-6.7/gdb/linespec.c 2007-10-14 23:31:03.000000000 +0200 +@@ -398,12 +398,14 @@ add_matching_methods (int method_counter + + /* Check for special case of looking for member that + doesn't have a mangled name provided. This will happen +- when we have in-charge and not-in-charge constructors. ++ when we have in-charge and not-in-charge ctors/dtors. + Since we don't have a mangled name to work with, if we +- look for the symbol, we can only find the class itself. ++ look for the symbol, we can at best find the class itself. + We can find the information we need in the minimal symbol + table which has the full member name information we need. */ +- if (strlen (phys_name) <= strlen (class_name)) ++ if (strlen (phys_name) <= strlen (class_name) ++ || (strlen (phys_name) == strlen (class_name) + 1 ++ && phys_name[0] == '~')) + return add_minsym_members (class_name, phys_name, msym_arr); + + /* Destructor is handled by caller, don't add it to +@@ -1731,6 +1733,11 @@ collect_methods (char *copy, struct type + { + int i1 = 0; /* Counter for the symbol array. */ + ++#if 0 ++ /* Ignore this special method for getting destructors because ++ find_methods is more robust and can handle multiple ++ destructors which is the case when gcc generates a not-in-charge ++ vs an in-charge destructor. */ + if (destructor_name_p (copy, t)) + { + /* Destructors are a special case. */ +@@ -1749,6 +1756,7 @@ collect_methods (char *copy, struct type + } + } + else ++#endif + i1 = find_methods (t, copy, SYMBOL_LANGUAGE (sym_class), sym_arr, msym_arr); + + return i1; diff --git a/gdb-6.3-focus-cmd-prev-test.patch b/gdb-6.3-focus-cmd-prev-test.patch new file mode 100644 index 0000000..88f52f1 --- /dev/null +++ b/gdb-6.3-focus-cmd-prev-test.patch @@ -0,0 +1,28 @@ +--- /dev/null 2008-03-23 13:41:46.072650180 +0100 ++++ gdb-6.3/gdb/testsuite/gdb.base/focus-cmd-prev.exp 2008-03-23 23:46:45.000000000 +0100 +@@ -0,0 +1,25 @@ ++# Copyright 2008 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++if $tracelevel then { ++ strace $tracelevel ++} ++ ++gdb_exit ++gdb_start ++ ++gdb_test "focus cmd" ++gdb_test "focus prev" diff --git a/gdb-6.3-framepczero-20040927.patch b/gdb-6.3-framepczero-20040927.patch new file mode 100644 index 0000000..a8dae6b --- /dev/null +++ b/gdb-6.3-framepczero-20040927.patch @@ -0,0 +1,28 @@ +2004-09-27 Andrew Cagney + + * frame.c (get_prev_frame): Stop backtrace when a zero PC and + successive normal frames. + +Index: gdb-6.8.50.20081128/gdb/frame.c +=================================================================== +--- gdb-6.8.50.20081128.orig/gdb/frame.c 2008-12-04 01:34:37.000000000 +0100 ++++ gdb-6.8.50.20081128/gdb/frame.c 2008-12-04 01:35:47.000000000 +0100 +@@ -1566,6 +1566,18 @@ get_prev_frame (struct frame_info *this_ + return NULL; + } + ++ if (this_frame->level > 0 ++#if 0 ++ && backtrace_past_zero_pc ++#endif ++ && get_frame_type (this_frame) == NORMAL_FRAME ++ && get_frame_type (get_next_frame (this_frame)) == NORMAL_FRAME ++ && get_frame_pc (this_frame) == 0) ++ { ++ frame_debug_got_null_frame (this_frame, "zero PC"); ++ return NULL; ++ } ++ + return get_prev_frame_1 (this_frame); + } + diff --git a/gdb-6.3-gcore-thread-20050204.patch b/gdb-6.3-gcore-thread-20050204.patch new file mode 100644 index 0000000..7da5240 --- /dev/null +++ b/gdb-6.3-gcore-thread-20050204.patch @@ -0,0 +1,25 @@ +2005-02-07 Jeff Johnston + + * linux-nat.c (linux_nat_xfer_memory): Don't use + linux_proc_xfer_memory for ia64. + +Index: gdb-6.8.50.20081209/gdb/linux-nat.c +=================================================================== +--- gdb-6.8.50.20081209.orig/gdb/linux-nat.c 2008-12-10 01:22:23.000000000 +0100 ++++ gdb-6.8.50.20081209/gdb/linux-nat.c 2008-12-10 01:25:26.000000000 +0100 +@@ -4123,10 +4123,15 @@ linux_xfer_partial (struct target_ops *o + return linux_nat_xfer_osdata (ops, object, annex, readbuf, writebuf, + offset, len); + ++#ifndef NATIVE_XFER_UNWIND_TABLE ++ /* FIXME: For ia64, we cannot currently use linux_proc_xfer_memory ++ for accessing thread storage. Revert when Bugzilla 147436 ++ is fixed. */ + xfer = linux_proc_xfer_partial (ops, object, annex, readbuf, writebuf, + offset, len); + if (xfer != 0) + return xfer; ++#endif + + return super_xfer_partial (ops, object, annex, readbuf, writebuf, + offset, len); diff --git a/gdb-6.3-gstack-20050411.patch b/gdb-6.3-gstack-20050411.patch new file mode 100644 index 0000000..5e54928 --- /dev/null +++ b/gdb-6.3-gstack-20050411.patch @@ -0,0 +1,115 @@ +2004-11-23 Andrew Cagney + + * Makefile.in (uninstall-gstack, install-gstack): New rules, add + to install and uninstall. + * gstack.sh, gstack.1: New files. + +Index: gdb-6.8.50.20090226/gdb/Makefile.in +=================================================================== +--- gdb-6.8.50.20090226.orig/gdb/Makefile.in 2009-02-26 22:09:59.000000000 +0100 ++++ gdb-6.8.50.20090226/gdb/Makefile.in 2009-02-26 22:10:22.000000000 +0100 +@@ -973,7 +973,7 @@ install: all install-only + + # The "install-only" target also installs the syscalls' XML files in + # the system. +-install-only: $(CONFIG_INSTALL) xml-syscall-install ++install-only: install-gstack $(CONFIG_INSTALL) xml-syscall-install + transformed_name=`t='$(program_transform_name)'; \ + echo gdb | sed -e "$$t"` ; \ + if test "x$$transformed_name" = x; then \ +@@ -1005,9 +1005,26 @@ install-tui: + $(DESTDIR)$(man1dir) ; \ + $(INSTALL_DATA) $(srcdir)/gdb.1 \ + $(DESTDIR)$(man1dir)/$$transformed_name.1 ++GSTACK=gstack ++.PHONY: install-gstack ++install-gstack: ++ transformed_name=`t='$(program_transform_name)'; \ ++ echo $(GSTACK) | sed -e "$$t"` ; \ ++ if test "x$$transformed_name" = x; then \ ++ transformed_name=$(GSTACK) ; \ ++ else \ ++ true ; \ ++ fi ; \ ++ $(SHELL) $(srcdir)/../mkinstalldirs $(DESTDIR)$(bindir) ; \ ++ $(INSTALL_PROGRAM) $(srcdir)/$(GSTACK).sh \ ++ $(DESTDIR)$(bindir)/$$transformed_name$(EXEEXT) ; \ ++ : $(SHELL) $(srcdir)/../mkinstalldirs \ ++ $(DESTDIR)$(man1dir) ; \ ++ : $(INSTALL_DATA) $(srcdir)/gstack.1 \ ++ $(DESTDIR)$(man1dir)/$$transformed_name.1 + + +-uninstall: force $(CONFIG_UNINSTALL) ++uninstall: force uninstall-gstack $(CONFIG_UNINSTALL) + transformed_name=`t='$(program_transform_name)'; \ + echo gdb | sed -e $$t` ; \ + if test "x$$transformed_name" = x; then \ +@@ -1029,6 +1046,17 @@ uninstall-tui: + fi ; \ + rm -f $(DESTDIR)$(bindir)/$$transformed_name$(EXEEXT) \ + $(DESTDIR)$(man1dir)/$$transformed_name.1 ++.PHONY: uninstall-gstack ++uninstall-gstack: ++ transformed_name=`t='$(program_transform_name)'; \ ++ echo $(GSTACK) | sed -e $$t` ; \ ++ if test "x$$transformed_name" = x; then \ ++ transformed_name=$(GSTACK) ; \ ++ else \ ++ true ; \ ++ fi ; \ ++ rm -f $(DESTDIR)$(bindir)/$$transformed_name$(EXEEXT) \ ++ $(DESTDIR)$(man1dir)/$$transformed_name.1 + + # The C++ name parser can be built standalone for testing. + test-cp-name-parser.o: cp-name-parser.c +Index: gdb-6.8.50.20090226/gdb/gstack.sh +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8.50.20090226/gdb/gstack.sh 2009-02-26 22:10:05.000000000 +0100 +@@ -0,0 +1,45 @@ ++#!/bin/sh ++ ++if test $# -ne 1; then ++ echo "Usage: `basename $0 .sh` " 1>&2 ++ exit 1 ++fi ++ ++if test ! -r /proc/$1; then ++ echo "Process $1 not found." 1>&2 ++ exit 1 ++fi ++ ++# GDB doesn't allow "thread apply all bt" when the process isn't ++# threaded; need to peek at the process to determine if that or the ++# simpler "bt" should be used. ++ ++backtrace="bt" ++if test -d /proc/$1/task ; then ++ # Newer kernel; has a task/ directory. ++ if test `ls /proc/$1/task | wc -l` -gt 1 2>/dev/null ; then ++ backtrace="thread apply all bt" ++ fi ++elif test -f /proc/$1/maps ; then ++ # Older kernel; go by it loading libpthread. ++ if grep -e libpthread /proc/$1/maps > /dev/null 2>&1 ; then ++ backtrace="thread apply all bt" ++ fi ++fi ++ ++GDB=${GDB:-gdb} ++ ++if $GDB -nx --quiet --batch --readnever > /dev/null 2>&1; then ++ readnever=--readnever ++else ++ readnever= ++fi ++ ++# Run GDB, strip out unwanted noise. ++$GDB --quiet $readnever -nx /proc/$1/exe $1 <&1 | ++$backtrace ++EOF ++sed -n \ ++ -e 's/^(gdb) //' \ ++ -e '/^#/p' \ ++ -e '/^Thread/p' diff --git a/gdb-6.3-gstack-without-path-20060414.patch b/gdb-6.3-gstack-without-path-20060414.patch new file mode 100644 index 0000000..ffc4b69 --- /dev/null +++ b/gdb-6.3-gstack-without-path-20060414.patch @@ -0,0 +1,34 @@ +Index: gdb-6.3/gdb/gstack.sh +=================================================================== +--- gdb-6.3.orig/gdb/gstack.sh 2006-02-14 17:21:05.000000000 -0200 ++++ gdb-6.3/gdb/gstack.sh 2006-04-14 03:17:12.000000000 -0300 +@@ -17,17 +17,17 @@ fi + backtrace="bt" + if test -d /proc/$1/task ; then + # Newer kernel; has a task/ directory. +- if test `ls /proc/$1/task | wc -l` -gt 1 2>/dev/null ; then ++ if test `/bin/ls /proc/$1/task | /usr/bin/wc -l` -gt 1 2>/dev/null ; then + backtrace="thread apply all bt" + fi + elif test -f /proc/$1/maps ; then + # Older kernel; go by it loading libpthread. +- if grep -e libpthread /proc/$1/maps > /dev/null 2>&1 ; then ++ if /bin/grep -e libpthread /proc/$1/maps > /dev/null 2>&1 ; then + backtrace="thread apply all bt" + fi + fi + +-GDB=${GDB:-gdb} ++GDB=${GDB:-/usr/bin/gdb} + + if $GDB -nx --quiet --batch --readnever > /dev/null 2>&1; then + readnever=--readnever +@@ -39,7 +39,7 @@ fi + $GDB --quiet $readnever -nx /proc/$1/exe $1 <&1 | + $backtrace + EOF +-sed -n \ ++/bin/sed -n \ + -e 's/^(gdb) //' \ + -e '/^#/p' \ + -e '/^Thread/p' diff --git a/gdb-6.3-ia64-gcore-page0-20050421.patch b/gdb-6.3-ia64-gcore-page0-20050421.patch new file mode 100644 index 0000000..093d641 --- /dev/null +++ b/gdb-6.3-ia64-gcore-page0-20050421.patch @@ -0,0 +1,20 @@ +Index: gdb-6.8.50.20081128/gdb/gcore.c +=================================================================== +--- gdb-6.8.50.20081128.orig/gdb/gcore.c 2008-09-11 16:27:34.000000000 +0200 ++++ gdb-6.8.50.20081128/gdb/gcore.c 2008-12-01 16:39:04.000000000 +0100 +@@ -475,8 +475,14 @@ gcore_copy_callback (bfd *obfd, asection + if (size > total_size) + size = total_size; + ++ /* Warn if read error occurs except if we were trying to read the ++ first page for ia64. The first page is marked readable, but it cannot ++ be read. */ + if (target_read_memory (bfd_section_vma (obfd, osec) + offset, +- memhunk, size) != 0) ++ memhunk, size) != 0 ++ && (strcmp (gdbarch_bfd_arch_info (current_gdbarch)->arch_name, ++ "ia64") ++ || bfd_section_vma (obfd, osec) != 0)) + { + warning (_("Memory read failed for corefile section, %s bytes at 0x%s."), + plongest (size), paddr (bfd_section_vma (obfd, osec))); diff --git a/gdb-6.3-ia64-gcore-speedup-20050714.patch b/gdb-6.3-ia64-gcore-speedup-20050714.patch new file mode 100644 index 0000000..a9d4377 --- /dev/null +++ b/gdb-6.3-ia64-gcore-speedup-20050714.patch @@ -0,0 +1,126 @@ +2005-07-14 Jeff Johnsotn + + * linux-nat.c (linux_nat_xfer_memory): Incorporate Fujitsu + work-around to use /proc/mem for storage, but to fall-back + to PTRACE for ia64 rse register areas. + * ia64-linux-nat.c (ia64_rse_slot_num): New static function. + (ia64_rse_skip_regs): Ditto. + (ia64_linux_check_stack_region): New function. + +Index: gdb-6.8.50.20090226/gdb/linux-nat.c +=================================================================== +--- gdb-6.8.50.20090226.orig/gdb/linux-nat.c 2009-02-27 07:51:44.000000000 +0100 ++++ gdb-6.8.50.20090226/gdb/linux-nat.c 2009-02-28 07:19:05.000000000 +0100 +@@ -4386,15 +4386,38 @@ linux_xfer_partial (struct target_ops *o + return linux_nat_xfer_osdata (ops, object, annex, readbuf, writebuf, + offset, len); + +-#ifndef NATIVE_XFER_UNWIND_TABLE +- /* FIXME: For ia64, we cannot currently use linux_proc_xfer_memory +- for accessing thread storage. Revert when Bugzilla 147436 +- is fixed. */ + xfer = linux_proc_xfer_partial (ops, object, annex, readbuf, writebuf, + offset, len); + if (xfer != 0) +- return xfer; ++ { ++#ifdef NATIVE_XFER_UNWIND_TABLE ++ struct mem_region range; ++ range.lo = memaddr; ++ range.hi = memaddr + len; ++ ++ /* FIXME: For ia64, we cannot currently use ++ linux_proc_xfer_partial for accessing rse register storage. ++ Revert when Bugzilla 147436 is fixed. */ ++#ifdef NATIVE_XFER_UNWIND_TABLE ++ extern int ia64_linux_check_stack_region (struct lwp_info *lwp, ++ void *range); ++#endif ++ if (iterate_over_lwps (ia64_linux_check_stack_region, &range) != NULL) ++ { /* This region contains ia64 rse registers, we have to re-read. */ ++ int xxfer; ++ ++ /* Re-read register stack area. */ ++ xxfer = super_xfer_partial (ops, object, annex, ++ readbuf + (range.lo - memaddr), ++ writebuf + (range.lo - memaddr), ++ offset + (range.lo - memaddr), ++ range.hi - range.lo); ++ if (xxfer == 0) ++ xfer = 0; ++ } + #endif ++ return xfer; ++ } + + return super_xfer_partial (ops, object, annex, readbuf, writebuf, + offset, len); +Index: gdb-6.8.50.20090226/gdb/ia64-linux-nat.c +=================================================================== +--- gdb-6.8.50.20090226.orig/gdb/ia64-linux-nat.c 2009-02-23 01:03:49.000000000 +0100 ++++ gdb-6.8.50.20090226/gdb/ia64-linux-nat.c 2009-02-28 07:18:10.000000000 +0100 +@@ -809,6 +809,64 @@ ia64_linux_xfer_partial (struct target_o + + void _initialize_ia64_linux_nat (void); + ++/* ++ * Note: taken from ia64_tdep.c ++ * ++ */ ++ ++static __inline__ unsigned long ++ia64_rse_slot_num (unsigned long addr) ++{ ++ return (addr >> 3) & 0x3f; ++} ++ ++/* Skip over a designated number of registers in the backing ++ store, remembering every 64th position is for NAT. */ ++static __inline__ unsigned long ++ia64_rse_skip_regs (unsigned long addr, long num_regs) ++{ ++ long delta = ia64_rse_slot_num(addr) + num_regs; ++ ++ if (num_regs < 0) ++ delta -= 0x3e; ++ return addr + ((num_regs + delta/0x3f) << 3); ++} ++ ++/* ++ * Check mem_region is stack or not. If stack, /proc//mem cannot return ++ * expected value. ++ */ ++int ia64_linux_check_stack_region(struct lwp_info *ti, struct mem_region *range) ++{ ++ CORE_ADDR addr; ++ int error; ++ unsigned long bsp, cfm, bspstore; ++ long sof; ++ pid_t pid = ptid_get_lwp(ti->ptid); ++ bsp = ptrace(PTRACE_PEEKUSER, pid, PT_AR_BSP ,NULL); ++ if (bsp == (unsigned long)-1) { ++ return 1; ++ } ++ /* stack is allocated by one-segment, not separated into several segments. ++ So, we only have to check whether bsp is in *range* or not. */ ++ if((range->lo <= bsp) && (bsp <= range->hi)) { ++ bspstore = ptrace(PTRACE_PEEKUSER, pid, PT_AR_BSPSTORE, NULL); ++ cfm = ptrace(PTRACE_PEEKUSER, pid, PT_CFM, NULL); ++ sof = cfm & 0x3f; ++ bsp = ia64_rse_skip_regs(bsp, -sof); ++ range->lo = bspstore; ++ range->hi = bsp; ++ /* we have to check the size of dirty register stack area */ ++ /* ++ fprintf_unfiltered(gdb_stdlog, "<%d> <%p> <%lx> <%p> <%p>\n", ++ pid, bsp, sof, range->lo, range->hi); ++ */ ++ return 1; ++ } ++ ++ return 0; ++} ++ + void + _initialize_ia64_linux_nat (void) + { diff --git a/gdb-6.3-ia64-info-frame-fix-20050725.patch b/gdb-6.3-ia64-info-frame-fix-20050725.patch new file mode 100644 index 0000000..3b2bd9a --- /dev/null +++ b/gdb-6.3-ia64-info-frame-fix-20050725.patch @@ -0,0 +1,110 @@ +2005-07-25 Jeff Johnstno + + * libunwind-frame.c (libunwind_frame_prev_register): Check valuep + is not NULL before copying cursor address into it. + +testsuite: +2005-07-25 Jeff Johnstno + + * gdb.arch/ia64-sigtramp.exp: New test. + * gdb.arch/ia64-sigtramp.c: Ditto. + +2008-02-24 Jan Kratochvil + + Port to GDB-6.8pre. (Only the testcase has remained.) + +--- gdb-6.3/gdb/testsuite/gdb.arch/ia64-sigtramp.c.fix 2005-07-25 16:42:46.000000000 -0400 ++++ gdb-6.3/gdb/testsuite/gdb.arch/ia64-sigtramp.c 2005-07-25 16:42:08.000000000 -0400 +@@ -0,0 +1,23 @@ ++#include ++#include ++ ++int *l; ++ ++void x (int sig) ++{ ++ printf ("in signal handler for signal %d\n", sig); ++} ++ ++int main() ++{ ++ int k; ++ ++ signal (SIGSEGV, &x); ++ ++ k = *l; ++ ++ printf ("k is %d\n", k); ++ ++ return 0; ++} ++ +--- gdb-6.3/gdb/testsuite/gdb.arch/ia64-sigtramp.exp.fix 2005-07-25 16:42:50.000000000 -0400 ++++ gdb-6.3/gdb/testsuite/gdb.arch/ia64-sigtramp.exp 2005-07-25 16:42:01.000000000 -0400 +@@ -0,0 +1,66 @@ ++# Copyright 2005 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++# Please email any bugs, comments, and/or additions to this file to: ++# bug-gdb@prep.ai.mit.edu ++ ++# This file was written by Jeff Johnston (jjohnstn@redhat.com) ++ ++if $tracelevel then { ++ strace $tracelevel ++} ++ ++# ++# test running programs ++# ++set prms_id 0 ++set bug_id 0 ++ ++if ![istarget "ia64-*-*"] then { ++ return ++} ++ ++set testfile "ia64-sigtramp" ++set srcfile ${testfile}.c ++set binfile ${objdir}/${subdir}/${testfile} ++ ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug additional_flags=-w}] != "" } { ++ gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail." ++} ++ ++if [get_compiler_info ${binfile}] { ++ return -1 ++} ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++if ![runto_main] then { ++ fail "Can't run to main" ++ return 0 ++} ++ ++gdb_test "handle SIGSEGV" "SIGSEGV.*Yes.*Yes.*Yes.*Segmentation fault" ++gdb_test "next" "" "first next" ++gdb_test "next" "Program received signal SIGSEGV.*" "getting SIGSEGV" ++gdb_breakpoint "x" ++gdb_test "continue" "Breakpoint.*x.*" "continue to x" ++ ++gdb_test "f 1" ".*signal handler called.*" "frame 1" ++gdb_test "info frame" "Stack level 1.*p63 at .*" "info sigtramp frame" ++ diff --git a/gdb-6.3-ia64-sigill-20051115.patch b/gdb-6.3-ia64-sigill-20051115.patch new file mode 100644 index 0000000..5c94160 --- /dev/null +++ b/gdb-6.3-ia64-sigill-20051115.patch @@ -0,0 +1,116 @@ +2005-11-15 Jeff Johnston + + * linux-thread-db.c (thread_db_wait): Don't bother continuing if + the wait result indicates the program terminated with a signal. + * linux-nat.c (linux_nat_wait): For SIGILL and SIGTRAP, don't + throw away the event if the user has specified nostop noprint. + +gdb/testsuite: + +2005-11-15 Jeff Johnston + + * gdb.arch/ia64-sigill.c: New test. + * gdb.arch/ia64-sigill.exp: Ditto. + +Index: gdb-6.8.50.20081128/gdb/testsuite/gdb.arch/ia64-sigill.exp +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8.50.20081128/gdb/testsuite/gdb.arch/ia64-sigill.exp 2008-12-02 21:10:57.000000000 +0100 +@@ -0,0 +1,59 @@ ++# Copyright 2005 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++# Please email any bugs, comments, and/or additions to this file to: ++# bug-gdb@prep.ai.mit.edu ++ ++# This file was written by Jeff Johnston (jjohnstn@redhat.com) ++ ++if $tracelevel then { ++ strace $tracelevel ++} ++ ++# ++# test running programs ++# ++set prms_id 0 ++set bug_id 0 ++ ++if ![istarget "ia64-*-*"] then { ++ return ++} ++ ++set testfile "ia64-sigill" ++set srcfile ${testfile}.c ++set binfile ${objdir}/${subdir}/${testfile} ++ ++# Deliberately compile with pthreads, even though test is single-threaded. ++# We want to force gdb thread code to be exercised. ++if { [gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug additional_flags=-w}] != "" } { ++ gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail." ++} ++ ++if [get_compiler_info ${binfile}] { ++ return -1 ++} ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++# We set up SIGILL nostop, noprint, pass and then run the program. ++# We expect to just see a normal run. ++gdb_test "handle SIGILL nostop noprint" "SIGILL.*No.*No.*Yes.*" "handle sigill" ++gdb_test "run" "Starting program.*ia64-sigill.*\[New thread.*\].*hello world.*Program exited normally." "run to exit" ++ +Index: gdb-6.8.50.20081128/gdb/testsuite/gdb.arch/ia64-sigill.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8.50.20081128/gdb/testsuite/gdb.arch/ia64-sigill.c 2008-12-02 21:10:57.000000000 +0100 +@@ -0,0 +1,8 @@ ++#include ++ ++int main() ++{ ++ printf ("hello world\n"); ++ return 0; ++} ++ +Index: gdb-6.8.50.20081128/gdb/linux-nat.c +=================================================================== +--- gdb-6.8.50.20081128.orig/gdb/linux-nat.c 2008-12-02 19:04:38.000000000 +0100 ++++ gdb-6.8.50.20081128/gdb/linux-nat.c 2008-12-02 21:11:11.000000000 +0100 +@@ -2974,7 +2974,8 @@ retry: + threads can be a bit time-consuming so if we want decent + performance with heavily multi-threaded programs, especially when + they're using a high frequency timer, we'd better avoid it if we +- can. */ ++ can. For possible trap signals like SIGTRAP and SIGILL, don't ++ avoid reporting. */ + + if (WIFSTOPPED (status)) + { +@@ -2992,7 +2993,9 @@ retry: + && inf->stop_soon == NO_STOP_QUIETLY + && signal_stop_state (signo) == 0 + && signal_print_state (signo) == 0 +- && signal_pass_state (signo) == 1) ++ && signal_pass_state (signo) == 1 ++ && signo != TARGET_SIGNAL_ILL ++ && signo != TARGET_SIGNAL_TRAP) + { + /* FIMXE: kettenis/2001-06-06: Should we resume all threads + here? It is not clear we should. GDB may not expect diff --git a/gdb-6.3-ia64-sigtramp-fp-20050926.patch b/gdb-6.3-ia64-sigtramp-fp-20050926.patch new file mode 100644 index 0000000..528afbf --- /dev/null +++ b/gdb-6.3-ia64-sigtramp-fp-20050926.patch @@ -0,0 +1,163 @@ +2005-09-27 Jeff Johnston + + * libunwind-frame.c (libunwind_frame_cache): Save the current + stack pointer in the cache. + (libunwind_sigtramp_frame_this_id): New function. + (libunwind_sigtramp_frame_unwind): New unwinder. + (libunwind_sigtramp_frame_sniffer): Return + libunwind_sigtramp_frame_unwind address. + * libunwind-frame.h (libunwind_sigtramp_frame_this_id): New + prototype. + * ia64-tdep.c (ia64_libunwind_sigtramp_frame_this_id): Calculate + the base address using the current stack pointer plus a fixed + offset. + +2007-10-14 Jan Kratochvil + + Port to GDB-6.7. + +2008-02-24 Jan Kratochvil + + Port to GDB-6.8pre. + +2008-04-16 Yi Zhan + + Fix a compilation error on a typo. + +Index: gdb-6.8.50.20081128/gdb/libunwind-frame.c +=================================================================== +--- gdb-6.8.50.20081128.orig/gdb/libunwind-frame.c 2008-05-06 20:37:46.000000000 +0200 ++++ gdb-6.8.50.20081128/gdb/libunwind-frame.c 2008-12-02 19:46:26.000000000 +0100 +@@ -61,6 +61,7 @@ static unw_word_t (*unw_find_dyn_list_p) + struct libunwind_frame_cache + { + CORE_ADDR base; ++ CORE_ADDR sp; + CORE_ADDR func_addr; + unw_cursor_t cursor; + unw_addr_space_t as; +@@ -133,6 +134,7 @@ libunwind_frame_cache (struct frame_info + unw_accessors_t *acc; + unw_addr_space_t as; + unw_word_t fp; ++ unw_word_t sp; + unw_regnum_t uw_sp_regnum; + struct libunwind_frame_cache *cache; + struct libunwind_descr *descr; +@@ -174,14 +176,30 @@ libunwind_frame_cache (struct frame_info + : __LITTLE_ENDIAN); + + unw_init_remote_p (&cache->cursor, as, this_frame); ++ ++ /* For the base address, we have a small problem. The majority ++ of the time, we can get the stack pointer of the previous ++ frame to use as a frame pointer. In the case where we have ++ a signal trampoline, the stack may change due to a sigaltstack ++ being set up. In that case, the normal mechanism will give us ++ an address in the regular stack which is not at the end of the ++ sigaltstack as we want. To handle this, we record the stack ++ address so the caller may calculate a more correct base address ++ to use. */ ++ uw_sp_regnum = descr->gdb2uw (gdbarch_sp_regnum (gdbarch)); ++ ret = unw_get_reg_p (&cache->cursor, uw_sp_regnum, &sp); ++ if (ret < 0) ++ { ++ unw_destroy_addr_space_p (as); ++ error (_("Can't get libunwind sp register.")); ++ } ++ + if (unw_step_p (&cache->cursor) < 0) + { + unw_destroy_addr_space_p (as); + return NULL; + } + +- /* To get base address, get sp from previous frame. */ +- uw_sp_regnum = descr->gdb2uw (gdbarch_sp_regnum (gdbarch)); + ret = unw_get_reg_p (&cache->cursor, uw_sp_regnum, &fp); + if (ret < 0) + { +@@ -189,6 +207,7 @@ libunwind_frame_cache (struct frame_info + error (_("Can't get libunwind sp register.")); + } + ++ cache->sp = (CORE_ADDR)sp; + cache->base = (CORE_ADDR)fp; + cache->as = as; + +@@ -376,6 +395,31 @@ libunwind_search_unwind_table (void *as, + di, pi, need_unwind_info, args); + } + ++void ++libunwind_sigtramp_frame_this_id (struct frame_info *this_frame, ++ void **this_cache, ++ struct frame_id *this_id) ++{ ++ struct libunwind_frame_cache *cache = ++ libunwind_frame_cache (this_frame, this_cache); ++ ++ /* Unlike a regular frame, we can't use the normal frame pointer ++ mechanism because a sigaltstack may have been used. Instead, ++ we return the current stack pointer for the caller to use ++ to calculate the base address. */ ++ if (cache != NULL) ++ (*this_id) = frame_id_build (cache->sp, cache->func_addr); ++ else ++ (*this_id) = null_frame_id; ++} ++ ++static const struct frame_unwind libunwind_sigtramp_frame_unwind = ++{ ++ SIGTRAMP_FRAME, ++ libunwind_sigtramp_frame_this_id, ++ libunwind_frame_prev_register ++}; ++ + /* Verify if we are in a sigtramp frame and we can use libunwind to unwind. */ + int + libunwind_sigtramp_frame_sniffer (const struct frame_unwind *self, +Index: gdb-6.8.50.20081128/gdb/libunwind-frame.h +=================================================================== +--- gdb-6.8.50.20081128.orig/gdb/libunwind-frame.h 2008-05-06 20:37:46.000000000 +0200 ++++ gdb-6.8.50.20081128/gdb/libunwind-frame.h 2008-12-02 19:38:55.000000000 +0100 +@@ -52,6 +52,9 @@ void libunwind_frame_set_descr (struct g + + void libunwind_frame_this_id (struct frame_info *this_frame, void **this_cache, + struct frame_id *this_id); ++void libunwind_sigtramp_frame_this_id (struct frame_info *this_frame, ++ void **this_cache, ++ struct frame_id *this_id); + struct value *libunwind_frame_prev_register (struct frame_info *this_frame, + void **this_cache, int regnum); + void libunwind_frame_dealloc_cache (struct frame_info *self, void *cache); +Index: gdb-6.8.50.20081128/gdb/ia64-tdep.c +=================================================================== +--- gdb-6.8.50.20081128.orig/gdb/ia64-tdep.c 2008-12-02 19:04:32.000000000 +0100 ++++ gdb-6.8.50.20081128/gdb/ia64-tdep.c 2008-12-02 21:09:46.000000000 +0100 +@@ -2964,7 +2964,7 @@ ia64_libunwind_sigtramp_frame_this_id (s + struct frame_id id; + CORE_ADDR prev_ip; + +- libunwind_frame_this_id (this_frame, this_cache, &id); ++ libunwind_sigtramp_frame_this_id (this_frame, this_cache, &id); + if (frame_id_eq (id, null_frame_id)) + { + (*this_id) = null_frame_id; +@@ -2976,8 +2976,14 @@ ia64_libunwind_sigtramp_frame_this_id (s + get_frame_register (this_frame, IA64_BSP_REGNUM, buf); + bsp = extract_unsigned_integer (buf, 8); + +- /* For a sigtramp frame, we don't make the check for previous ip being 0. */ +- (*this_id) = frame_id_build_special (id.stack_addr, id.code_addr, bsp); ++ /* For a sigtramp frame, we don't make the check for previous ip being 0. ++ We also must calculate the frame pointer because libunwind will give ++ us back the current stack pointer instead of the frame pointer since ++ it cannot figure this out when in a sigaltstack. We make a basic ++ assumption of 16 (default size) + 8 bytes for sigcontext address. ++ FIXME: if libunwind were to export the frame pointer address, we ++ could eliminate the assumption and get the actual value. */ ++ (*this_id) = frame_id_build_special (id.stack_addr + 24, id.code_addr, bsp); + + if (gdbarch_debug >= 1) + fprintf_unfiltered (gdb_stdlog, diff --git a/gdb-6.3-ia64-sigtramp-frame-20050708.patch b/gdb-6.3-ia64-sigtramp-frame-20050708.patch new file mode 100644 index 0000000..1862f97 --- /dev/null +++ b/gdb-6.3-ia64-sigtramp-frame-20050708.patch @@ -0,0 +1,158 @@ +2005-07-08 Jeff Johnston + + * ia64-tdep.c (ia64_sigtramp_frame_prev_register): Build + pseudo-registers the same as ia64_pseudo_register_read. + +2008-04-16 Yi Zhan + + * ia64-tdep.c (ia64_sigtramp_frame_prev_register): Fix an + ISO C compliance compilation error. + +2008-02-12 Jan Kratochvil + + Port to gdb-6.8.50.20081128, follow the upstream change: + http://sourceware.org/cgi-bin/cvsweb.cgi/src/gdb/ia64-tdep.c.diff?cvsroot=src&r1=1.176&r2=1.177 + +Index: gdb-6.8.50.20081128/gdb/ia64-tdep.c +=================================================================== +--- gdb-6.8.50.20081128.orig/gdb/ia64-tdep.c 2008-11-26 06:27:48.000000000 +0100 ++++ gdb-6.8.50.20081128/gdb/ia64-tdep.c 2008-12-02 19:04:32.000000000 +0100 +@@ -2107,6 +2107,94 @@ ia64_sigtramp_frame_prev_register (struc + return frame_unwind_got_constant (this_frame, regnum, pc); + } + ++ /* Red Hat patch begin. */ ++ else if (IA64_NAT0_REGNUM <= regnum && regnum <= IA64_NAT31_REGNUM) ++ { ++ /* NAT pseudo registers 0-31: get them from UNAT. ++ * "copied" from ia64_pseudo_register_read() */ ++ ULONGEST unatN_val; ++ ULONGEST unat; ++ read_memory (cache->saved_regs[IA64_UNAT_REGNUM], (char *) &unat, ++ register_size (current_gdbarch, IA64_UNAT_REGNUM)); ++ unatN_val = (unat & (1LL << (regnum - IA64_NAT0_REGNUM))) != 0; ++ return frame_unwind_got_constant (this_frame, regnum, unatN_val); ++ } ++ else if (IA64_NAT32_REGNUM <= regnum && regnum <= IA64_NAT127_REGNUM) ++ { ++ /* NAT pseudo registers 32-127. ++ * "copied" from ia64_pseudo_register_read() ++ * FIXME: Not currently tested -- cannot get the frame to include ++ * NAT32-NAT127. */ ++ ULONGEST bsp; ++ ULONGEST cfm; ++ ULONGEST natN_val = 0; ++ CORE_ADDR gr_addr = 0, nat_addr = 0; ++ ++ read_memory (cache->saved_regs[IA64_BSP_REGNUM], (char *) &bsp, ++ register_size (current_gdbarch, IA64_BSP_REGNUM)); ++ read_memory (cache->saved_regs[IA64_CFM_REGNUM], (char *) &cfm, ++ register_size (current_gdbarch, IA64_CFM_REGNUM)); ++ ++ /* The bsp points at the end of the register frame so we ++ subtract the size of frame from it to get start of register frame. */ ++ bsp = rse_address_add (bsp, -(cfm & 0x7f)); ++ ++ if ((cfm & 0x7f) > regnum - V32_REGNUM) ++ gr_addr = rse_address_add (bsp, (regnum - V32_REGNUM)); ++ ++ if (gr_addr != 0) ++ { ++ /* Compute address of nat collection bits */ ++ CORE_ADDR nat_collection; ++ int nat_bit; ++ nat_addr = gr_addr | 0x1f8; ++ /* If our nat collection address is bigger than bsp, we have to get ++ the nat collection from rnat. Otherwise, we fetch the nat ++ collection from the computed address. FIXME: Do not know if ++ RNAT can be not stored in the frame--being extra cautious. */ ++ if (nat_addr >= bsp) ++ { ++ nat_addr = cache->saved_regs[IA64_RNAT_REGNUM]; ++ if (nat_addr != 0) ++ read_memory (nat_addr, (char *) &nat_collection, ++ register_size (current_gdbarch, IA64_RNAT_REGNUM)); ++ } ++ else ++ nat_collection = read_memory_integer (nat_addr, 8); ++ if (nat_addr != 0) ++ { ++ nat_bit = (gr_addr >> 3) & 0x3f; ++ natN_val = (nat_collection >> nat_bit) & 1; ++ return frame_unwind_got_constant (this_frame, regnum, natN_val); ++ } ++ } ++ warning (_("ia64_sigtramp_frame_prev_register: unhandled register %d"), ++ regnum); ++ } ++ else if (regnum == VBOF_REGNUM) ++ { ++ /* BOF pseudo register. ++ * "copied" from ia64_pseudo_register_read() ++ * ++ * A virtual register frame start is provided for user convenience. ++ * It can be calculated as the bsp - sof (sizeof frame). */ ++ ULONGEST bsp; ++ ULONGEST cfm; ++ ULONGEST bof; ++ ++ read_memory (cache->saved_regs[IA64_BSP_REGNUM], (char *) &bsp, ++ register_size (current_gdbarch, IA64_BSP_REGNUM)); ++ read_memory (cache->saved_regs[IA64_CFM_REGNUM], (char *) &cfm, ++ register_size (current_gdbarch, IA64_CFM_REGNUM)); ++ ++ /* The bsp points at the end of the register frame so we ++ subtract the size of frame from it to get beginning of frame. */ ++ bof = rse_address_add (bsp, -(cfm & 0x7f)); ++ ++ return frame_unwind_got_constant (this_frame, regnum, bof); ++ } ++ /* Red Hat patch end. */ ++ + else if ((regnum >= IA64_GR32_REGNUM && regnum <= IA64_GR127_REGNUM) + || (regnum >= V32_REGNUM && regnum <= V127_REGNUM)) + { +@@ -2121,7 +2209,42 @@ ia64_sigtramp_frame_prev_register (struc + return frame_unwind_got_constant (this_frame, regnum, 0); + } + +- else /* All other registers not listed above. */ ++ /* Red Hat patch begin. */ ++ else if (VP0_REGNUM <= regnum && regnum <= VP63_REGNUM) ++ { ++ /* VP 0-63. ++ * "copied" from ia64_pseudo_register_read() ++ * ++ * FIXME: Not currently tested--cannot get the frame to include PR. */ ++ CORE_ADDR pr_addr = 0; ++ ++ pr_addr = cache->saved_regs[IA64_PR_REGNUM]; ++ if (pr_addr != 0) ++ { ++ ULONGEST pr; ++ ULONGEST cfm; ++ ULONGEST prN_val; ++ read_memory (pr_addr, (char *) &pr, ++ register_size (current_gdbarch, IA64_PR_REGNUM)); ++ read_memory (cache->saved_regs[IA64_CFM_REGNUM], (char *) &cfm, ++ register_size (current_gdbarch, IA64_CFM_REGNUM)); ++ ++ /* Get the register rename base for this frame and adjust the ++ * register name to take rotation into account. */ ++ if (VP16_REGNUM <= regnum && regnum <= VP63_REGNUM) ++ { ++ int rrb_pr = (cfm >> 32) & 0x3f; ++ regnum = VP16_REGNUM + ((regnum - VP16_REGNUM) + rrb_pr) % 48; ++ } ++ prN_val = (pr & (1LL << (regnum - VP0_REGNUM))) != 0; ++ return frame_unwind_got_constant (this_frame, regnum, prN_val); ++ } ++ warning (_("ia64_sigtramp_frame_prev_register: unhandled register %d"), ++ regnum); ++ } ++ /* Red Hat patch end. */ ++ ++ /* All other registers not listed above. */ + { + CORE_ADDR addr = cache->saved_regs[regnum]; + diff --git a/gdb-6.3-inferior-notification-20050721.patch b/gdb-6.3-inferior-notification-20050721.patch new file mode 100644 index 0000000..5a014ff --- /dev/null +++ b/gdb-6.3-inferior-notification-20050721.patch @@ -0,0 +1,322 @@ +2005-07-21 Jeff Johnston + + * gdb.base/attach-32.exp: New test for attaching in 32-bit + mode on 64-bit systems. + * gdb.base/attach-32.c: Ditto. + * gdb.base/attach-32b.c: Ditto. + +2007-12-26 Jan Kratochvil + + * gdb.base/attach-32.exp: Fix forgotten $GDBFLAGS as set. + +Index: gdb-6.8.50.20081128/gdb/testsuite/gdb.base/attach-32.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8.50.20081128/gdb/testsuite/gdb.base/attach-32.c 2008-12-07 10:06:03.000000000 +0100 +@@ -0,0 +1,20 @@ ++/* This program is intended to be started outside of gdb, and then ++ attached to by gdb. Thus, it simply spins in a loop. The loop ++ is exited when & if the variable 'should_exit' is non-zero. (It ++ is initialized to zero in this program, so the loop will never ++ exit unless/until gdb sets the variable to non-zero.) ++ */ ++#include ++ ++int should_exit = 0; ++ ++int main () ++{ ++ int local_i = 0; ++ ++ while (! should_exit) ++ { ++ local_i++; ++ } ++ return 0; ++} +Index: gdb-6.8.50.20081128/gdb/testsuite/gdb.base/attach-32.exp +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8.50.20081128/gdb/testsuite/gdb.base/attach-32.exp 2008-12-07 10:08:52.000000000 +0100 +@@ -0,0 +1,252 @@ ++# Copyright 2005 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++# ++# This test was based on attach.exp and modified for 32/64 bit Linux systems. */ ++ ++if $tracelevel then { ++ strace $tracelevel ++} ++ ++set prms_id 0 ++set bug_id 0 ++ ++# On HP-UX 11.0, this test is causing a process running the program ++# "attach" to be left around spinning. Until we figure out why, I am ++# commenting out the test to avoid polluting tiamat (our 11.0 nightly ++# test machine) with these processes. RT ++# ++# Setting the magic bit in the target app should work. I added a ++# "kill", and also a test for the R3 register warning. JB ++if { ![istarget "x86_64*-*linux*"] ++ && ![istarget "powerpc64*-*linux*"]} { ++ return 0 ++} ++ ++# are we on a target board ++if [is_remote target] then { ++ return 0 ++} ++ ++set testfile "attach-32" ++set srcfile ${testfile}.c ++set srcfile2 ${testfile}b.c ++set binfile ${objdir}/${subdir}/${testfile} ++set binfile2 ${objdir}/${subdir}/${testfile}b ++set escapedbinfile [string_to_regexp ${objdir}/${subdir}/${testfile}] ++ ++#execute_anywhere "rm -f ${binfile} ${binfile2}" ++remote_exec build "rm -f ${binfile} ${binfile2}" ++# For debugging this test ++# ++#log_user 1 ++ ++# build the first test case ++# ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable [list debug "additional_flags=-m32"]] != "" } { ++ gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail." ++} ++ ++# Build the in-system-call test ++ ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile2}" "${binfile2}" executable [list debug "additional_flags=-m32"]] != "" } { ++ gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail." ++} ++ ++if [get_compiler_info ${binfile}] { ++ return -1 ++} ++ ++proc do_attach_tests {} { ++ global gdb_prompt ++ global binfile ++ global escapedbinfile ++ global srcfile ++ global testfile ++ global objdir ++ global subdir ++ global timeout ++ global testpid ++ ++ # Verify that we can "see" the variable "should_exit" in the ++ # program, and that it is zero. ++ ++ gdb_test "print should_exit" " = 0" "after attach-32, print should_exit" ++ ++ # Verify that we can modify the variable "should_exit" in the ++ # program. ++ ++ gdb_test "set should_exit=1" "" "after attach-32, set should_exit" ++ ++ # Verify that the modification really happened. ++ ++ send_gdb "tbreak 19\n" ++ gdb_expect { ++ -re "reakpoint .*at.*$srcfile, line 19.*$gdb_prompt $" { ++ pass "after attach-32, set tbreak postloop" ++ } ++ -re "$gdb_prompt $" { ++ fail "after attach-32, set tbreak postloop" ++ } ++ timeout { ++ fail "(timeout) after attach-32, set tbreak postloop" ++ } ++ } ++ send_gdb "continue\n" ++ gdb_expect { ++ -re "main.*at.*$srcfile:19.*$gdb_prompt $" { ++ pass "after attach-32, reach tbreak postloop" ++ } ++ -re "$gdb_prompt $" { ++ fail "after attach-32, reach tbreak postloop" ++ } ++ timeout { ++ fail "(timeout) after attach-32, reach tbreak postloop" ++ } ++ } ++ ++ # Allow the test process to exit, to cleanup after ourselves. ++ ++ gdb_test "continue" "Program exited normally." "after attach-32, exit" ++ ++ # Make sure we don't leave a process around to confuse ++ # the next test run (and prevent the compile by keeping ++ # the text file busy), in case the "set should_exit" didn't ++ # work. ++ ++ remote_exec build "kill -9 ${testpid}" ++ ++ # Start the program running and then wait for a bit, to be sure ++ # that it can be attached to. ++ ++ set testpid [eval exec $binfile &] ++ exec sleep 2 ++ if { [istarget "*-*-cygwin*"] } { ++ # testpid is the Cygwin PID, GDB uses the Windows PID, which might be ++ # different due to the way fork/exec works. ++ set testpid [ exec ps -e | gawk "{ if (\$1 == $testpid) print \$4; }" ] ++ } ++ ++ # Verify that we can attach to the process, and find its a.out ++ # when we're cd'd to some directory that doesn't contain the ++ # a.out. (We use the source path set by the "dir" command.) ++ ++ gdb_test "dir ${objdir}/${subdir}" "Source directories searched: .*" \ ++ "set source path" ++ ++ gdb_test "cd /tmp" "Working directory /tmp." \ ++ "cd away from process working directory" ++ ++ # Explicitly flush out any knowledge of the previous attachment. ++ ++ set test "before attach-32-3, flush symbols" ++ gdb_test_multiple "symbol" "$test" { ++ -re "Discard symbol table from.*y or n. $" { ++ gdb_test "y" "No symbol file now." \ ++ "$test" ++ } ++ -re "No symbol file now.*$gdb_prompt $" { ++ pass "$test" ++ } ++ } ++ ++ gdb_test "exec" "No executable file now." \ ++ "before attach-32-3, flush exec" ++ ++ gdb_test "attach $testpid" \ ++ "Attaching to process $testpid.*Reading symbols from $escapedbinfile.*main.*at .*" \ ++ "attach-32 when process' a.out not in cwd" ++ ++ set test "after attach-32-3, exit" ++ gdb_test_multiple "kill" "$test" { ++ -re "Kill the program being debugged.*y or n. $" { ++ gdb_test "y" "" "$test" ++ } ++ } ++ ++ # Another "don't leave a process around" ++ remote_exec build "kill -9 ${testpid}" ++} ++ ++proc do_call_attach_tests {} { ++ global gdb_prompt ++ global binfile2 ++ global testpid ++ ++ # See if other registers are problems ++ ++ set test "info other register" ++ gdb_test_multiple "i r r3" "$test" { ++ -re "warning: reading register.*$gdb_prompt $" { ++ fail "$test" ++ } ++ -re "r3.*$gdb_prompt $" { ++ pass "$test" ++ } ++ } ++ ++ # Get rid of the process ++ ++ gdb_test "p should_exit = 1" ++ gdb_test "c" "Program exited normally." ++ ++ # Be paranoid ++ ++ remote_exec build "kill -9 ${testpid}" ++} ++ ++ ++# Start with a fresh gdb ++ ++gdb_exit ++set testpid [eval exec $binfile &] ++exec sleep 3 ++if { [istarget "*-*-cygwin*"] } { ++ # testpid is the Cygwin PID, GDB uses the Windows PID, which might be ++ # different due to the way fork/exec works. ++ set testpid [ exec ps -e | gawk "{ if (\$1 == $testpid) print \$4; }" ] ++} ++ ++set GDBFLAGS_orig $GDBFLAGS ++set GDBFLAGS "--pid=$testpid" ++gdb_start ++set GDBFLAGS $GDBFLAGS_orig ++ ++gdb_reinitialize_dir $srcdir/$subdir ++ ++# This is a test of gdb's ability to attach to a running process. ++ ++do_attach_tests ++ ++# Test attaching when the target is inside a system call ++ ++gdb_exit ++set testpid [eval exec $binfile2 &] ++exec sleep 3 ++if { [istarget "*-*-cygwin*"] } { ++ # testpid is the Cygwin PID, GDB uses the Windows PID, which might be ++ # different due to the way fork/exec works. ++ set testpid [ exec ps -e | gawk "{ if (\$1 == $testpid) print \$4; }" ] ++} ++ ++set GDBFLAGS_orig $GDBFLAGS ++set GDBFLAGS "--pid=$testpid" ++gdb_start ++set GDBFLAGS $GDBFLAGS_orig ++ ++gdb_reinitialize_dir $srcdir/$subdir ++do_call_attach_tests ++ ++return 0 +Index: gdb-6.8.50.20081128/gdb/testsuite/gdb.base/attach-32b.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8.50.20081128/gdb/testsuite/gdb.base/attach-32b.c 2008-12-07 10:06:03.000000000 +0100 +@@ -0,0 +1,24 @@ ++/* This program is intended to be started outside of gdb, and then ++ attached to by gdb. Thus, it simply spins in a loop. The loop ++ is exited when & if the variable 'should_exit' is non-zero. (It ++ is initialized to zero in this program, so the loop will never ++ exit unless/until gdb sets the variable to non-zero.) ++ */ ++#include ++#include ++#include ++ ++int should_exit = 0; ++ ++int main () ++{ ++ int local_i = 0; ++ ++ sleep( 10 ); /* System call causes register fetch to fail */ ++ /* This is a known HPUX "feature" */ ++ while (! should_exit) ++ { ++ local_i++; ++ } ++ return (0); ++} diff --git a/gdb-6.3-inheritance-20050324.patch b/gdb-6.3-inheritance-20050324.patch new file mode 100644 index 0000000..433b6f7 --- /dev/null +++ b/gdb-6.3-inheritance-20050324.patch @@ -0,0 +1,26 @@ +2005-03-24 Jeff Johnston + + * valops.c (check_field_in): Use check_typedef for base classes + to avoid problems with opaque type references. + +Index: gdb-6.8.50.20081128/gdb/valops.c +=================================================================== +--- gdb-6.8.50.20081128.orig/gdb/valops.c 2008-12-08 10:56:11.000000000 +0100 ++++ gdb-6.8.50.20081128/gdb/valops.c 2008-12-08 10:59:14.000000000 +0100 +@@ -2484,8 +2484,14 @@ check_field (struct type *type, const ch + } + + for (i = TYPE_N_BASECLASSES (type) - 1; i >= 0; i--) +- if (check_field (TYPE_BASECLASS (type, i), name)) +- return 1; ++ { ++ /* Check the base classes. Make sure we have the real type for ++ each base class as opposed to an opaque declaration. */ ++ struct type *baseclass = check_typedef (TYPE_BASECLASS (type, i)); ++ ++ if (check_field (baseclass, name)) ++ return 1; ++ } + + return 0; + } diff --git a/gdb-6.3-inheritancetest-20050726.patch b/gdb-6.3-inheritancetest-20050726.patch new file mode 100644 index 0000000..74d793c --- /dev/null +++ b/gdb-6.3-inheritancetest-20050726.patch @@ -0,0 +1,153 @@ +2005-07-26 Jeff Johnston + + * gdb.cp/b146835.exp: New testcase. + * gdb.cp/b146835.cc: Ditto. + * gdb.cp/b146835b.cc: Ditto. + * gdb.cp/b146835.h: Ditto. + +--- gdb-6.3/gdb/testsuite/gdb.cp/b146835b.cc.fix3 2005-07-26 16:47:12.000000000 -0400 ++++ gdb-6.3/gdb/testsuite/gdb.cp/b146835b.cc 2005-07-26 16:53:31.000000000 -0400 +@@ -0,0 +1,11 @@ ++#include "b146835.h" ++ ++C::C() { d = 0; x = 3; } ++ ++int C::z (char *s) { return 0; } ++ ++C::~C() {} ++ ++void A::funcD (class E *e, class D *d) {} ++void A::funcE (E *e, D *d) {} ++void A::funcF (unsigned long x, D *d) {} +--- gdb-6.3/gdb/testsuite/gdb.cp/b146835.cc.fix3 2005-07-26 16:47:20.000000000 -0400 ++++ gdb-6.3/gdb/testsuite/gdb.cp/b146835.cc 2005-07-26 16:46:50.000000000 -0400 +@@ -0,0 +1,32 @@ ++#include "b146835.h" ++#include ++ ++class F : public C { ++ ++protected: ++ ++ virtual void funcA (unsigned long a, B *b); ++ virtual void funcB (E *e); ++ virtual void funcC (unsigned long x, bool y); ++ ++ char *s1, *s2; ++ bool b1; ++ int k; ++ ++public: ++ void foo() { ++ std::cout << "foo" << std::endl; ++ } ++}; ++ ++ ++void F::funcA (unsigned long a, B *b) {} ++void F::funcB (E *e) {} ++void F::funcC (unsigned long x, bool y) {} ++ ++int main() ++{ ++ F f; ++ f.foo(); ++} ++ +--- gdb-6.3/gdb/testsuite/gdb.cp/b146835.exp.fix3 2005-07-26 16:47:26.000000000 -0400 ++++ gdb-6.3/gdb/testsuite/gdb.cp/b146835.exp 2005-07-26 16:46:50.000000000 -0400 +@@ -0,0 +1,55 @@ ++# This testcase is part of GDB, the GNU debugger. ++ ++# Copyright 2005 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++# Check that GDB can properly print an inherited member variable ++# (Bugzilla 146835) ++ ++if $tracelevel { ++ strace $tracelevel ++} ++ ++set prms_id 0 ++set bug_id 0 ++ ++set testfile "b146835" ++set srcfile ${testfile}.cc ++set srcfile2 ${testfile}b.cc ++set binfile ${objdir}/${subdir}/${testfile} ++if {[gdb_compile "${srcdir}/${subdir}/${srcfile} ${srcdir}/${subdir}/${srcfile2}" "${binfile}" executable {debug c++}] != "" } { ++ return -1 ++} ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++# ++# Run to `main' where we begin our tests. ++# ++ ++if ![runto_main] then { ++ gdb_suppress_tests ++} ++ ++gdb_test "break 'F::foo()'" "" ++gdb_continue_to_breakpoint "First line foo" ++ ++# Verify that we can access the inherited member d ++gdb_test "p d" ".*(struct D \*.).*0x0" "Verify inherited member d accessible" ++ +--- gdb-6.3/gdb/testsuite/gdb.cp/b146835.h.fix3 2005-07-26 16:47:36.000000000 -0400 ++++ gdb-6.3/gdb/testsuite/gdb.cp/b146835.h 2005-07-26 16:53:18.000000000 -0400 +@@ -0,0 +1,36 @@ ++ ++class A { ++ ++protected: ++ ++ virtual void funcA (unsigned long a, class B *b) = 0; ++ virtual void funcB (class E *e) = 0; ++ virtual void funcC (unsigned long x, bool y) = 0; ++ ++ void funcD (class E *e, class D* d); ++ virtual void funcE (E *e, D *d); ++ virtual void funcF (unsigned long x, D *d); ++}; ++ ++ ++class C : public A { ++ ++protected: ++ ++ int x; ++ class K *k; ++ class H *h; ++ ++ D *d; ++ ++ class W *w; ++ class N *n; ++ class L *l; ++ unsigned long *r; ++ ++public: ++ ++ C(); ++ int z (char *s); ++ virtual ~C(); ++}; diff --git a/gdb-6.3-large-core-20051206.patch b/gdb-6.3-large-core-20051206.patch new file mode 100644 index 0000000..73e8139 --- /dev/null +++ b/gdb-6.3-large-core-20051206.patch @@ -0,0 +1,316 @@ +2005-12-14 Jeff Johnston + + * symfile-mem.c (read_memory): New static read callback function. + (symfile_add_from_memory): Pass read_memory to bfd instead of + target_read_memory. + * target.c (target_xfer_memory): Add support for LONGEST len and + change all callers. + (deprecated_debug_xfer_memory, target_read_memory): Ditto. + (target_write_memory, do_xfer_memory): Ditto. + (target_xfer_memory_partial, target_read_memory_partial): Ditto. + (target_write_memory_partial): Ditto. + * infptrace.c (child_xfer_memory): Ditto. + * linux-nat.c (linux_nat_xfer_memory): Ditto. + (linux_nat_proc_xfer_memory): Ditto. + * dcache.c (dcache_xfer_memory): Ditto. + * exec.c (xfer_memory): Ditto. + * remote.c (remote_xfer_memory): Ditto. + * remote-sim.c (gdbsim_xfer_interior_memory): Ditto. + * target.h: Change prototypes for functions changed above. + * linux-nat.h: Ditto. + * remote.h: Ditto. + * dcache.h: Ditto. + +2007-10-15 Jan Kratochvil + + Port to GDB-6.7. + +Index: gdb-6.8.50.20090226/gdb/symfile-mem.c +=================================================================== +--- gdb-6.8.50.20090226.orig/gdb/symfile-mem.c 2009-02-21 17:14:49.000000000 +0100 ++++ gdb-6.8.50.20090226/gdb/symfile-mem.c 2009-02-28 07:22:09.000000000 +0100 +@@ -56,6 +56,14 @@ + #include "elf/common.h" + + ++/* Local callback routine to pass to bfd to read from target memory, ++ using a len constrained to INT_MAX. */ ++static int ++read_target_memory (bfd_vma addr, bfd_byte *buf, int len) ++{ ++ return target_read_memory (addr, buf, (LONGEST)len); ++} ++ + /* Read inferior memory at ADDR to find the header of a loaded object file + and read its in-core symbols out of inferior memory. TEMPL is a bfd + representing the target's format. NAME is the name to use for this +@@ -76,7 +84,7 @@ symbol_file_add_from_memory (struct bfd + error (_("add-symbol-file-from-memory not supported for this target")); + + nbfd = bfd_elf_bfd_from_remote_memory (templ, addr, &loadbase, +- target_read_memory); ++ read_target_memory); + if (nbfd == NULL) + error (_("Failed to read a valid object file image from memory.")); + +Index: gdb-6.8.50.20090226/gdb/target.c +=================================================================== +--- gdb-6.8.50.20090226.orig/gdb/target.c 2009-02-27 00:04:32.000000000 +0100 ++++ gdb-6.8.50.20090226/gdb/target.c 2009-02-28 07:22:09.000000000 +0100 +@@ -57,7 +57,7 @@ static int nosymbol (char *, CORE_ADDR * + + static void tcomplain (void) ATTR_NORETURN; + +-static int nomemory (CORE_ADDR, char *, int, int, struct target_ops *); ++static LONGEST nomemory (CORE_ADDR, char *, int, int, struct target_ops *); + + static int return_zero (void); + +@@ -286,7 +286,7 @@ target_create_inferior (char *exec_file, + } + + +-static int ++static LONGEST + nomemory (CORE_ADDR memaddr, char *myaddr, int len, int write, + struct target_ops *t) + { +@@ -507,7 +507,7 @@ update_current_target (void) + (void (*) (struct regcache *)) + noprocess); + de_fault (deprecated_xfer_memory, +- (int (*) (CORE_ADDR, gdb_byte *, int, int, struct mem_attrib *, struct target_ops *)) ++ (LONGEST (*) (CORE_ADDR, gdb_byte *, LONGEST, int, struct mem_attrib *, struct target_ops *)) + nomemory); + de_fault (to_files_info, + (void (*) (struct target_ops *)) +@@ -1237,7 +1237,7 @@ target_xfer_partial (struct target_ops * + it makes no progress, and then return how much was transferred). */ + + int +-target_read_memory (CORE_ADDR memaddr, gdb_byte *myaddr, int len) ++target_read_memory (CORE_ADDR memaddr, gdb_byte *myaddr, LONGEST len) + { + if (target_read (¤t_target, TARGET_OBJECT_MEMORY, NULL, + myaddr, memaddr, len) == len) +@@ -1247,7 +1247,7 @@ target_read_memory (CORE_ADDR memaddr, g + } + + int +-target_write_memory (CORE_ADDR memaddr, const gdb_byte *myaddr, int len) ++target_write_memory (CORE_ADDR memaddr, const gdb_byte *myaddr, LONGEST len) + { + if (target_write (¤t_target, TARGET_OBJECT_MEMORY, NULL, + myaddr, memaddr, len) == len) +@@ -2777,8 +2777,8 @@ debug_to_prepare_to_store (struct regcac + fprintf_unfiltered (gdb_stdlog, "target_prepare_to_store ()\n"); + } + +-static int +-deprecated_debug_xfer_memory (CORE_ADDR memaddr, bfd_byte *myaddr, int len, ++static LONGEST ++deprecated_debug_xfer_memory (CORE_ADDR memaddr, bfd_byte *myaddr, LONGEST len, + int write, struct mem_attrib *attrib, + struct target_ops *target) + { +@@ -2788,8 +2788,8 @@ deprecated_debug_xfer_memory (CORE_ADDR + attrib, target); + + fprintf_unfiltered (gdb_stdlog, +- "target_xfer_memory (%s, xxx, %d, %s, xxx) = %d", +- paddress (memaddr), len, write ? "write" : "read", ++ "target_xfer_memory (%s, xxx, %ld, %s, xxx) = %d", ++ paddress (memaddr), (long) len, write ? "write" : "read", + retval); + + if (retval > 0) +Index: gdb-6.8.50.20090226/gdb/target.h +=================================================================== +--- gdb-6.8.50.20090226.orig/gdb/target.h 2009-02-27 00:04:32.000000000 +0100 ++++ gdb-6.8.50.20090226/gdb/target.h 2009-02-28 07:22:09.000000000 +0100 +@@ -376,10 +376,10 @@ struct target_ops + NOTE: cagney/2004-10-01: This has been entirely superseeded by + to_xfer_partial and inferior inheritance. */ + +- int (*deprecated_xfer_memory) (CORE_ADDR memaddr, gdb_byte *myaddr, +- int len, int write, +- struct mem_attrib *attrib, +- struct target_ops *target); ++ LONGEST (*deprecated_xfer_memory) (CORE_ADDR memaddr, gdb_byte *myaddr, ++ LONGEST len, int write, ++ struct mem_attrib *attrib, ++ struct target_ops *target); + + void (*to_files_info) (struct target_ops *); + int (*to_insert_breakpoint) (struct bp_target_info *); +@@ -679,13 +679,14 @@ extern DCACHE *target_dcache; + + extern int target_read_string (CORE_ADDR, char **, int, int *); + +-extern int target_read_memory (CORE_ADDR memaddr, gdb_byte *myaddr, int len); ++extern int target_read_memory (CORE_ADDR memaddr, gdb_byte *myaddr, ++ LONGEST len); + + extern int target_write_memory (CORE_ADDR memaddr, const gdb_byte *myaddr, +- int len); ++ LONGEST len); + +-extern int xfer_memory (CORE_ADDR, gdb_byte *, int, int, +- struct mem_attrib *, struct target_ops *); ++extern LONGEST xfer_memory (CORE_ADDR, gdb_byte *, LONGEST, int, ++ struct mem_attrib *, struct target_ops *); + + /* Fetches the target's memory map. If one is found it is sorted + and returned, after some consistency checking. Otherwise, NULL +Index: gdb-6.8.50.20090226/gdb/dcache.c +=================================================================== +--- gdb-6.8.50.20090226.orig/gdb/dcache.c 2009-01-03 06:57:51.000000000 +0100 ++++ gdb-6.8.50.20090226/gdb/dcache.c 2009-02-28 07:22:09.000000000 +0100 +@@ -524,9 +524,9 @@ dcache_free (DCACHE *dcache) + + This routine is indended to be called by remote_xfer_ functions. */ + +-int ++LONGEST + dcache_xfer_memory (DCACHE *dcache, CORE_ADDR memaddr, gdb_byte *myaddr, +- int len, int should_write) ++ LONGEST len, int should_write) + { + int i; + int (*xfunc) (DCACHE *dcache, CORE_ADDR addr, gdb_byte *ptr); +Index: gdb-6.8.50.20090226/gdb/dcache.h +=================================================================== +--- gdb-6.8.50.20090226.orig/gdb/dcache.h 2009-01-03 06:57:51.000000000 +0100 ++++ gdb-6.8.50.20090226/gdb/dcache.h 2009-02-28 07:22:09.000000000 +0100 +@@ -35,7 +35,7 @@ void dcache_free (DCACHE *); + + /* Simple to call from _xfer_memory */ + +-int dcache_xfer_memory (DCACHE *cache, CORE_ADDR mem, gdb_byte *my, +- int len, int should_write); ++LONGEST dcache_xfer_memory (DCACHE *cache, CORE_ADDR mem, gdb_byte *my, ++ LONGEST len, int should_write); + + #endif /* DCACHE_H */ +Index: gdb-6.8.50.20090226/gdb/exec.c +=================================================================== +--- gdb-6.8.50.20090226.orig/gdb/exec.c 2009-02-22 20:35:47.000000000 +0100 ++++ gdb-6.8.50.20090226/gdb/exec.c 2009-02-28 07:22:09.000000000 +0100 +@@ -464,8 +464,8 @@ map_vmap (bfd *abfd, bfd *arch) + The same routine is used to handle both core and exec files; + we just tail-call it with more arguments to select between them. */ + +-int +-xfer_memory (CORE_ADDR memaddr, gdb_byte *myaddr, int len, int write, ++LONGEST ++xfer_memory (CORE_ADDR memaddr, gdb_byte *myaddr, LONGEST len, int write, + struct mem_attrib *attrib, struct target_ops *target) + { + int res; +Index: gdb-6.8.50.20090226/gdb/linux-nat.c +=================================================================== +--- gdb-6.8.50.20090226.orig/gdb/linux-nat.c 2009-02-28 07:22:02.000000000 +0100 ++++ gdb-6.8.50.20090226/gdb/linux-nat.c 2009-02-28 07:22:32.000000000 +0100 +@@ -4407,7 +4407,7 @@ linux_xfer_partial (struct target_ops *o + #endif + if (iterate_over_lwps (ia64_linux_check_stack_region, &range) != NULL) + { /* This region contains ia64 rse registers, we have to re-read. */ +- int xxfer; ++ LONGEST xxfer; + + /* Re-read register stack area. */ + xxfer = super_xfer_partial (ops, object, annex, +Index: gdb-6.8.50.20090226/gdb/remote.c +=================================================================== +--- gdb-6.8.50.20090226.orig/gdb/remote.c 2009-02-25 03:14:22.000000000 +0100 ++++ gdb-6.8.50.20090226/gdb/remote.c 2009-02-28 07:22:09.000000000 +0100 +@@ -25,6 +25,7 @@ + #include "gdb_string.h" + #include + #include ++#include + #include "inferior.h" + #include "bfd.h" + #include "symfile.h" +@@ -5683,12 +5684,19 @@ handle_notification (char *buf, size_t l + if SHOULD_WRITE is nonzero. Returns length of data written or + read; 0 for error. TARGET is unused. */ + +-static int +-remote_xfer_memory (CORE_ADDR mem_addr, gdb_byte *buffer, int mem_len, ++static LONGEST ++remote_xfer_memory (CORE_ADDR mem_addr, gdb_byte *buffer, LONGEST mem_len, + int should_write, struct mem_attrib *attrib, + struct target_ops *target) + { + int res; ++ int len; ++ ++ /* This routine is not set up to handle > INT_MAX bytes. */ ++ if (mem_len >= (LONGEST)INT_MAX) ++ return 0; ++ ++ len = (int)mem_len; + + set_general_thread (inferior_ptid); + +@@ -5697,7 +5705,7 @@ remote_xfer_memory (CORE_ADDR mem_addr, + else + res = remote_read_bytes (mem_addr, buffer, mem_len); + +- return res; ++ return (LONGEST)res; + } + + /* Sends a packet with content determined by the printf format string +Index: gdb-6.8.50.20090226/gdb/remote-sim.c +=================================================================== +--- gdb-6.8.50.20090226.orig/gdb/remote-sim.c 2009-02-23 19:31:23.000000000 +0100 ++++ gdb-6.8.50.20090226/gdb/remote-sim.c 2009-02-28 07:22:09.000000000 +0100 +@@ -754,11 +754,14 @@ gdbsim_prepare_to_store (struct regcache + + Returns the number of bytes transferred. */ + +-static int +-gdbsim_xfer_inferior_memory (CORE_ADDR memaddr, gdb_byte *myaddr, int len, ++static LONGEST ++gdbsim_xfer_inferior_memory (CORE_ADDR memaddr, gdb_byte *myaddr, LONGEST len, + int write, struct mem_attrib *attrib, + struct target_ops *target) + { ++ /* Convert to len type that sim_read and sim_write can handle. */ ++ int xfer_len = (int)len; ++ + /* If no program is running yet, then ignore the simulator for + memory. Pass the request down to the next target, hopefully + an exec file. */ +@@ -774,22 +777,22 @@ gdbsim_xfer_inferior_memory (CORE_ADDR m + printf_filtered ("gdbsim_xfer_inferior_memory: myaddr 0x"); + gdb_print_host_address (myaddr, gdb_stdout); + printf_filtered (", memaddr 0x%s, len %d, write %d\n", +- paddr_nz (memaddr), len, write); ++ paddr_nz (memaddr), xfer_len, write); + if (remote_debug && write) +- dump_mem (myaddr, len); ++ dump_mem (myaddr, xfer_len); + } + + if (write) + { +- len = sim_write (gdbsim_desc, memaddr, myaddr, len); ++ xfer_len = sim_write (gdbsim_desc, memaddr, myaddr, xfer_len); + } + else + { +- len = sim_read (gdbsim_desc, memaddr, myaddr, len); +- if (remote_debug && len > 0) +- dump_mem (myaddr, len); ++ xfer_len = sim_read (gdbsim_desc, memaddr, myaddr, xfer_len); ++ if (remote_debug && xfer_len > 0) ++ dump_mem (myaddr, xfer_len); + } +- return len; ++ return (LONGEST)xfer_len; + } + + static void diff --git a/gdb-6.3-linespec-20041213.patch b/gdb-6.3-linespec-20041213.patch new file mode 100644 index 0000000..eb373ef --- /dev/null +++ b/gdb-6.3-linespec-20041213.patch @@ -0,0 +1,464 @@ +[base] + +2007-09-21 Jan Kratochvil + + * linespec.c (add_minsym_members): Support also the `$allocate' and + `$delete' variants. + +2007-10-05 Jan Kratochvil + + * linespec.c (add_minsym_members): Support also the `$allocate' and + `$delete' variants. + (decode_variable): Renamed to ... + (decode_variable_1) ... here, its parameter NOT_FOUND_PTR and its + exception throwing was moved to ... + (decode_variable_not_found): ... a new function here. + (decode_variable): New function. + +2007-10-31 Jan Kratochvil + + Port to GDB-6.7. + +[ Remove decode_variable* for GDB-6.8+ as no longer needed. ] + +Index: gdb-6.8.50.20081128/gdb/linespec.c +=================================================================== +--- gdb-6.8.50.20081128.orig/gdb/linespec.c 2008-09-05 13:37:17.000000000 +0200 ++++ gdb-6.8.50.20081128/gdb/linespec.c 2008-12-04 01:43:36.000000000 +0100 +@@ -39,6 +39,7 @@ + #include "interps.h" + #include "mi/mi-cmds.h" + #include "target.h" ++#include "gdb_assert.h" + + /* We share this one with symtab.c, but it is not exported widely. */ + +@@ -78,7 +79,8 @@ static struct symtabs_and_lines find_met + + static int collect_methods (char *copy, struct type *t, + struct symbol *sym_class, +- struct symbol **sym_arr); ++ struct symbol **sym_arr, ++ struct minimal_symbol **msym_arr); + + static NORETURN void cplusplus_error (const char *name, + const char *fmt, ...) +@@ -87,11 +89,13 @@ static NORETURN void cplusplus_error (co + static int total_number_of_methods (struct type *type); + + static int find_methods (struct type *, char *, +- enum language, struct symbol **); ++ enum language, struct symbol **, ++ struct minimal_symbol **); + + static int add_matching_methods (int method_counter, struct type *t, + enum language language, +- struct symbol **sym_arr); ++ struct symbol **sym_arr, ++ struct minimal_symbol **msym_arr); + + static int add_constructors (int method_counter, struct type *t, + enum language language, +@@ -107,6 +111,9 @@ static int is_objc_method_format (const + static struct symtabs_and_lines decode_line_2 (struct symbol *[], + int, int, char ***); + ++static struct symtabs_and_lines decode_line_3 (struct minimal_symbol *[], ++ int, int, char ***); ++ + static struct symtab *symtab_from_filename (char **argptr, + char *p, int is_quote_enclosed, + int *not_found_ptr); +@@ -196,13 +203,18 @@ total_number_of_methods (struct type *ty + /* Recursive helper function for decode_line_1. + Look for methods named NAME in type T. + Return number of matches. +- Put matches in SYM_ARR, which should have been allocated with ++ Put symbol matches in SYM_ARR, which should have been allocated with + a size of total_number_of_methods (T) * sizeof (struct symbol *). ++ In a special case where we are looking for constructors, we may ++ have to return minimal symbols in the array: MSYM_ARR. This occurs ++ when the compiler does not generate mangled names for the constructor's ++ debug info because there are multiple versions of the constructor ++ (in-charge vs not-in-charge). + Note that this function is g++ specific. */ + + static int + find_methods (struct type *t, char *name, enum language language, +- struct symbol **sym_arr) ++ struct symbol **sym_arr, struct minimal_symbol **msym_arr) + { + int i1 = 0; + int ibase; +@@ -244,7 +256,7 @@ find_methods (struct type *t, char *name + if (strcmp_iw (name, method_name) == 0) + /* Find all the overloaded methods with that name. */ + i1 += add_matching_methods (method_counter, t, language, +- sym_arr + i1); ++ sym_arr + i1, msym_arr); + else if (strncmp (class_name, name, name_len) == 0 + && (class_name[name_len] == '\0' + || class_name[name_len] == '<')) +@@ -267,21 +279,100 @@ find_methods (struct type *t, char *name + if (i1 == 0) + for (ibase = 0; ibase < TYPE_N_BASECLASSES (t); ibase++) + i1 += find_methods (TYPE_BASECLASS (t, ibase), name, +- language, sym_arr + i1); ++ language, sym_arr + i1, msym_arr); + + return i1; + } + ++static int ++add_minsym_members (const char *class_name, ++ const char *member_name, ++ struct minimal_symbol **msym_arr) ++{ ++ char *completion_name; ++ char **list; ++ int i; ++ int comp_len; ++ int counter = 0; ++ ++ /* To find the member, we first cheat and use symbol completion. ++ This will give us a list of all the member names including ++ the function signature. */ ++ completion_name = xmalloc (strlen (class_name) + ++ strlen (member_name) + 9); ++ completion_name[0] = '\''; ++ strcpy (completion_name+1, class_name); ++ /* FIXME: make this the language class separator. */ ++ strcat (completion_name, "::"); ++ strcat (completion_name, member_name); ++ strcat (completion_name, "("); ++ list = make_symbol_completion_list (completion_name, ++ completion_name+1); ++ ++ /* Now that we have the list, we generate an array of their ++ corresponding minimal symbols. */ ++ counter = 0; ++ while (list && list[counter] != NULL) ++ { ++ msym_arr[counter] = lookup_minimal_symbol (list[counter], NULL, NULL); ++ ++counter; ++ } ++ ++ xfree (list); ++ ++ /* In the case of constructors, there may be in-charge vs not-in-charge ++ constructors. Check for names with $base which indicates not-in-charge ++ constructors. */ ++ comp_len = strlen (completion_name); ++ strcpy (completion_name + comp_len - 1, "$base("); ++ list = make_symbol_completion_list (completion_name, ++ completion_name+1); ++ ++ /* Again we have a list. Add their minimal symbols to the array. */ ++ i = 0; ++ while (list && list[i] != NULL) ++ { ++ msym_arr[counter] = lookup_minimal_symbol (list[i++], NULL, NULL); ++ ++counter; ++ } ++ xfree (list); ++ ++ /* Target also the allocating/deleting variants. */ ++ if (member_name[0] == '~') ++ strcpy (completion_name + comp_len - 1, "$delete("); ++ else ++ strcpy (completion_name + comp_len - 1, "$allocate("); ++ list = make_symbol_completion_list (completion_name, ++ completion_name+1); ++ ++ /* Again we have a list. Add their minimal symbols to the array. */ ++ i = 0; ++ while (list && list[i] != NULL) ++ { ++ msym_arr[counter] = lookup_minimal_symbol (list[i++], NULL, NULL); ++ ++counter; ++ } ++ xfree (list); ++ ++ xfree (completion_name); ++ ++ return counter; ++} ++ + /* Add the symbols associated to methods of the class whose type is T + and whose name matches the method indexed by METHOD_COUNTER in the + array SYM_ARR. Return the number of methods added. */ + + static int + add_matching_methods (int method_counter, struct type *t, +- enum language language, struct symbol **sym_arr) ++ enum language language, struct symbol **sym_arr, ++ struct minimal_symbol **msym_arr) + { + int field_counter; + int i1 = 0; ++ int cons_index = 0; ++ char *class_name = type_name_no_tag (t); ++ char **list = NULL; + + for (field_counter = TYPE_FN_FIELDLIST_LENGTH (t, method_counter) - 1; + field_counter >= 0; +@@ -306,6 +397,16 @@ add_matching_methods (int method_counter + else + phys_name = TYPE_FN_FIELD_PHYSNAME (f, field_counter); + ++ /* Check for special case of looking for member that ++ doesn't have a mangled name provided. This will happen ++ when we have in-charge and not-in-charge constructors. ++ Since we don't have a mangled name to work with, if we ++ look for the symbol, we can only find the class itself. ++ We can find the information we need in the minimal symbol ++ table which has the full member name information we need. */ ++ if (strlen (phys_name) <= strlen (class_name)) ++ return add_minsym_members (class_name, phys_name, msym_arr); ++ + /* Destructor is handled by caller, don't add it to + the list. */ + if (is_destructor_name (phys_name) != 0) +@@ -330,6 +431,9 @@ add_matching_methods (int method_counter + } + } + ++ if (list) ++ xfree (list); ++ + return i1; + } + +@@ -630,6 +734,146 @@ See set/show multiple-symbol.")); + discard_cleanups (old_chain); + return return_values; + } ++ ++/* Given a list of NELTS minimal symbols in MSYM_ARR, return a list of lines to ++ operate on (ask user if necessary). ++ If CANONICAL is non-NULL return a corresponding array of mangled names ++ as canonical line specs there. */ ++ ++static struct symtabs_and_lines ++decode_line_3 (struct minimal_symbol *msym_arr[], ++ int nelts, int funfirstline, ++ char ***canonical) ++{ ++ struct symtabs_and_lines values, return_values; ++ char *args, *arg1; ++ int i; ++ char *prompt; ++ char *symname; ++ struct cleanup *old_chain; ++ char **canonical_arr = (char **) NULL; ++ ++ values.sals = (struct symtab_and_line *) ++ alloca (nelts * sizeof (struct symtab_and_line)); ++ return_values.sals = (struct symtab_and_line *) ++ xmalloc (nelts * sizeof (struct symtab_and_line)); ++ old_chain = make_cleanup (xfree, return_values.sals); ++ ++ if (canonical) ++ { ++ canonical_arr = (char **) xmalloc (nelts * sizeof (char *)); ++ make_cleanup (xfree, canonical_arr); ++ memset (canonical_arr, 0, nelts * sizeof (char *)); ++ *canonical = canonical_arr; ++ } ++ ++ i = 0; ++ printf_unfiltered ("[0] cancel\n[1] all\n"); ++ while (i < nelts) ++ { ++ init_sal (&return_values.sals[i]); /* Initialize to zeroes. */ ++ init_sal (&values.sals[i]); ++ if (msym_arr[i]) ++ { ++ struct symtabs_and_lines msal = minsym_found (funfirstline, ++ msym_arr[i]); ++ memcpy (&values.sals[i], &msal.sals[0], ++ sizeof (struct symtab_and_line)); ++ if (values.sals[i].symtab) ++ printf_unfiltered ("[%d] %s at %s:%d\n", ++ (i + 2), ++ SYMBOL_PRINT_NAME (msym_arr[i]), ++ values.sals[i].symtab->filename, ++ values.sals[i].line); ++ else ++ printf_unfiltered ("[%d] %s at ?FILE:%d [No symtab? Probably broken debug info...]\n", ++ (i + 2), ++ SYMBOL_PRINT_NAME (msym_arr[i]), ++ values.sals[i].line); ++ ++ } ++ else ++ printf_unfiltered ("?HERE\n"); ++ i++; ++ } ++ ++ prompt = getenv ("PS2"); ++ if (prompt == NULL) ++ { ++ prompt = "> "; ++ } ++ args = command_line_input (prompt, 0, "overload-choice"); ++ ++ if (args == 0 || *args == 0) ++ error_no_arg ("one or more choice numbers"); ++ ++ i = 0; ++ while (*args) ++ { ++ int num; ++ ++ arg1 = args; ++ while (*arg1 >= '0' && *arg1 <= '9') ++ arg1++; ++ if (*arg1 && *arg1 != ' ' && *arg1 != '\t') ++ error ("Arguments must be choice numbers."); ++ ++ num = atoi (args); ++ ++ if (num == 0) ++ error ("canceled"); ++ else if (num == 1) ++ { ++ if (canonical_arr) ++ { ++ for (i = 0; i < nelts; i++) ++ { ++ if (canonical_arr[i] == NULL) ++ { ++ symname = SYMBOL_LINKAGE_NAME (msym_arr[i]); ++ canonical_arr[i] = savestring (symname, strlen (symname)); ++ } ++ } ++ } ++ memcpy (return_values.sals, values.sals, ++ (nelts * sizeof (struct symtab_and_line))); ++ return_values.nelts = nelts; ++ discard_cleanups (old_chain); ++ return return_values; ++ } ++ ++ if (num >= nelts + 2) ++ { ++ printf_unfiltered ("No choice number %d.\n", num); ++ } ++ else ++ { ++ num -= 2; ++ if (values.sals[num].pc) ++ { ++ if (canonical_arr) ++ { ++ symname = SYMBOL_LINKAGE_NAME (msym_arr[num]); ++ make_cleanup (xfree, symname); ++ canonical_arr[i] = savestring (symname, strlen (symname)); ++ } ++ return_values.sals[i++] = values.sals[num]; ++ values.sals[num].pc = 0; ++ } ++ else ++ { ++ printf_unfiltered ("duplicate request for %d ignored.\n", num); ++ } ++ } ++ ++ args = arg1; ++ while (*args == ' ' || *args == '\t') ++ args++; ++ } ++ return_values.nelts = i; ++ discard_cleanups (old_chain); ++ return return_values; ++} + + /* The parser of linespec itself. */ + +@@ -1438,35 +1682,47 @@ find_method (int funfirstline, char ***c + struct symbol **sym_arr = alloca (total_number_of_methods (t) + * sizeof (struct symbol *)); + ++ struct minimal_symbol **msym_arr = alloca (total_number_of_methods (t) ++ * sizeof (struct minimal_symbol *)); ++ ++ msym_arr[0] = NULL; ++ + /* Find all methods with a matching name, and put them in + sym_arr. */ + +- i1 = collect_methods (copy, t, sym_class, sym_arr); ++ i1 = collect_methods (copy, t, sym_class, sym_arr, msym_arr); + + if (i1 == 1) + { + /* There is exactly one field with that name. */ +- sym = sym_arr[0]; +- +- if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK) +- { +- values.sals = (struct symtab_and_line *) +- xmalloc (sizeof (struct symtab_and_line)); +- values.nelts = 1; +- values.sals[0] = find_function_start_sal (sym, +- funfirstline); +- } ++ if (msym_arr[0] != NULL) ++ return minsym_found (funfirstline, msym_arr[0]); + else + { +- values.sals = NULL; +- values.nelts = 0; ++ sym = sym_arr[0]; ++ ++ if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK) ++ { ++ values.sals = (struct symtab_and_line *) ++ xmalloc (sizeof (struct symtab_and_line)); ++ values.nelts = 1; ++ values.sals[0] = find_function_start_sal (sym, ++ funfirstline); ++ } ++ else ++ { ++ values.sals = NULL; ++ values.nelts = 0; ++ } ++ return values; + } +- return values; + } + if (i1 > 0) + { + /* There is more than one field with that name + (overloaded). Ask the user which one to use. */ ++ if (msym_arr[0] != NULL) ++ return decode_line_3 (msym_arr, i1, funfirstline, canonical); + return decode_line_2 (sym_arr, i1, funfirstline, canonical); + } + else +@@ -1493,11 +1748,12 @@ find_method (int funfirstline, char ***c + } + + /* Find all methods named COPY in the class whose type is T, and put +- them in SYM_ARR. Return the number of methods found. */ ++ them in SYM_ARR or MSYM_ARR. Return the number of methods found. */ + + static int + collect_methods (char *copy, struct type *t, +- struct symbol *sym_class, struct symbol **sym_arr) ++ struct symbol *sym_class, struct symbol **sym_arr, ++ struct minimal_symbol **msym_arr) + { + int i1 = 0; /* Counter for the symbol array. */ + +@@ -1518,7 +1774,7 @@ collect_methods (char *copy, struct type + } + } + else +- i1 = find_methods (t, copy, SYMBOL_LANGUAGE (sym_class), sym_arr); ++ i1 = find_methods (t, copy, SYMBOL_LANGUAGE (sym_class), sym_arr, msym_arr); + + return i1; + } diff --git a/gdb-6.3-mapping-zero-inode-test.patch b/gdb-6.3-mapping-zero-inode-test.patch new file mode 100644 index 0000000..8b4a8c8 --- /dev/null +++ b/gdb-6.3-mapping-zero-inode-test.patch @@ -0,0 +1,221 @@ +--- /dev/null 2008-05-02 23:36:22.370004160 +0200 ++++ gdb-6.8/gdb/testsuite/gdb.base/gcore-shmid0.exp 2008-05-03 22:36:56.000000000 +0200 +@@ -0,0 +1,120 @@ ++# Copyright 2007 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++# Please email any bugs, comments, and/or additions to this file to: ++# bug-gdb@prep.ai.mit.edu ++ ++# Test GDB's handling of gcore for mapping with a name but zero inode. ++ ++set testfile "gcore-shmid0" ++set srcfile ${testfile}.c ++set binfile ${objdir}/${subdir}/${testfile} ++ ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { ++ untested gcore.exp ++ return -1 ++} ++ ++# Start with a fresh gdb. ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++# Does this gdb support gcore? ++send_gdb "help gcore\n" ++gdb_expect { ++ -re "Undefined command: .gcore.*$gdb_prompt $" { ++ # gcore command not supported -- nothing to test here. ++ unsupported "gdb does not support gcore on this target" ++ return -1; ++ } ++ -re "Save a core file .*$gdb_prompt $" { ++ pass "help gcore" ++ } ++ -re ".*$gdb_prompt $" { ++ fail "help gcore" ++ } ++ timeout { ++ fail "help gcore (timeout)" ++ } ++} ++ ++if { ! [ runto_main ] } then { ++ untested gcore-shmid0.exp ++ return -1 ++} ++ ++gdb_breakpoint "initialized" ++gdb_breakpoint "unresolved" ++ ++set test "Continue to initialized." ++gdb_test_multiple "continue" $test { ++ -re "Breakpoint .*, initialized .* at .*\r\n$gdb_prompt $" { ++ pass $test ++ } ++ -re "Breakpoint .*, unresolved .* at .*\r\n$gdb_prompt $" { ++ unsupported $test ++ return -1 ++ } ++} ++ ++set escapedfilename [string_to_regexp ${objdir}/${subdir}/gcore-shmid0.test] ++ ++set test "save a corefile" ++gdb_test_multiple "gcore ${objdir}/${subdir}/gcore-shmid0.test" $test { ++ -re "Saved corefile ${escapedfilename}\[\r\n\]+$gdb_prompt $" { ++ pass $test ++ } ++ -re "Can't create a corefile\[\r\n\]+$gdb_prompt $" { ++ unsupported $test ++ } ++ eof { ++ fail $test ++ } ++} ++ ++# Be sure to remove the handle first. ++# But it would get removed even on a kill by GDB as the handle is already ++# deleted, just it is still attached. ++gdb_continue_to_end "finish" ++ ++set test "core-file command" ++gdb_test_multiple "core-file $objdir/$subdir/gcore-shmid0.test" $test { ++ -re ".* program is being debugged already.*y or n. $" { ++ # gdb_load may connect us to a gdbserver. ++ send_gdb "y\n" ++ exp_continue; ++ } ++ -re "Core was generated by .*\r\n\#0 .*\\\(\\\).*\r\n$gdb_prompt $" { ++ # The filename does not fit there anyway so do not check it. ++ pass $test ++ } ++ -re ".*registers from core file: File in wrong format.* $" { ++ fail "core-file command (could not read registers from core file)" ++ } ++} ++ ++set test "backtrace" ++gdb_test_multiple "bt" $test { ++ -re "#0 *initialized \\\(\\\) at .*#1 .* main \\\(.*$gdb_prompt $" { ++ pass $test ++ } ++ -re "#0 *initialized \\\(\\\) at .*Cannot access memory at address .*$gdb_prompt $" { ++ fail $test ++ } ++} +--- /dev/null 2008-05-02 23:36:22.370004160 +0200 ++++ gdb-6.8/gdb/testsuite/gdb.base/gcore-shmid0.c 2008-05-03 22:39:10.000000000 +0200 +@@ -0,0 +1,95 @@ ++/* Copyright 2007 Free Software Foundation, Inc. ++ ++ This file is part of GDB. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or (at ++ your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, but ++ WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place - Suite 330, ++ Boston, MA 02111-1307, USA. */ ++ ++/* ++ * Test GDB's handling of gcore for mapping with a name but zero inode. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* We need a backtrace through the stack. */ ++ ++static void ++initialized (void) ++{ ++} ++ ++static void ++unresolved (void) ++{ ++} ++ ++int ++main (void) ++{ ++ int sid; ++ unsigned int *addr = (void *) -1L; ++ int try; ++ ++ /* The generated SID will cycle with an increment of 32768, try until it ++ * wraps to 0. */ ++ ++ for (try = 0; addr == (void *) -1L; try++) ++ { ++ /* At least kernel-2.6.25-8.fc9.x86_64 just never returns the value 0 by ++ shmget(2). */ ++ if (try > 0x10000) ++ { ++ printf ("Problem no longer reproducible on this kernel (try %d)\n", ++ try); ++ unresolved (); ++ exit (1); ++ } ++ ++ sid = shmget ((key_t) rand (), 0x1000, IPC_CREAT | IPC_EXCL | 0777); ++ if (sid == -1) ++ { ++ printf ("shmget (%d, 0x1000, IPC_CREAT): errno %d\n", 0, errno); ++ exit (1); ++ } ++ ++ /* Use SID only if it is 0, retry it otherwise. */ ++ ++ if (sid == 0) ++ { ++ addr = shmat (sid, NULL, SHM_RND); ++ if (addr == (void *) -1L) ++ { ++ printf ("shmat (%d, NULL, SHM_RND): errno %d\n", sid, ++ errno); ++ exit (1); ++ } ++ } ++ if (shmctl (sid, IPC_RMID, NULL) != 0) ++ { ++ printf ("shmctl (%d, IPC_RMID, NULL): errno %d\n", sid, errno); ++ exit (1); ++ } ++ } ++ ++ initialized (); ++ ++ return 0; ++} diff --git a/gdb-6.3-nonthreaded-wp-20050117.patch b/gdb-6.3-nonthreaded-wp-20050117.patch new file mode 100644 index 0000000..6f49864 --- /dev/null +++ b/gdb-6.3-nonthreaded-wp-20050117.patch @@ -0,0 +1,119 @@ +[base] + +2007-10-13 Jan Kratochvil + + * linux-nat.c (iterate_over_lwps): Fixed missing LWP initialization for + current INFERIOR_PTID. + +2007-10-13 Jan Kratochvil + + * gdb.base/follow-child.exp, gdb.base/follow-child.c: New files. + +2007-10-16 Jan Kratochvil + + Port to GDB-6.7. + +2008-02-24 Jan Kratochvil + + Port to GDB-6.8pre. + +2008-08-25 Jan Kratochvil + + Remove the fix as causing an assertion failure for + gdb.base/checkpoint.exp and it is no longer needed for + gdb.base/follow-child.exp . + +Index: gdb-6.8cvs20080219/gdb/testsuite/gdb.base/follow-child.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8cvs20080219/gdb/testsuite/gdb.base/follow-child.c 2008-02-22 08:14:04.000000000 +0100 +@@ -0,0 +1,29 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2007 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++ Please email any bugs, comments, and/or additions to this file to: ++ bug-gdb@prep.ai.mit.edu */ ++ ++#include ++ ++int main() ++{ ++ fork (); ++ sleep (60); ++ return 0; ++} +Index: gdb-6.8cvs20080219/gdb/testsuite/gdb.base/follow-child.exp +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8cvs20080219/gdb/testsuite/gdb.base/follow-child.exp 2008-02-22 08:14:17.000000000 +0100 +@@ -0,0 +1,55 @@ ++# Copyright 2007 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++if $tracelevel then { ++ strace $tracelevel ++} ++ ++set prms_id 0 ++set bug_id 0 ++ ++set testfile follow-child ++set srcfile ${testfile}.c ++set binfile ${objdir}/${subdir}/${testfile} ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { ++ untested "Couldn't compile test program" ++ return -1 ++} ++ ++# Get things started. ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++# For C programs, "start" should stop in main(). ++ ++gdb_test "set follow-fork-mode child" "" ++set test "started" ++# GDB_RUN_CMD already checks for `Starting program:'. ++gdb_run_cmd ++sleep 5 ++send_gdb "\003" ++set test "break" ++gdb_test_multiple "" $test { ++ -re "Program received signal SIGINT.*$gdb_prompt $" { ++ pass $test ++ } ++ -re "\\\[New process \[0-9\]+\\\]" { ++ fail $test ++ } ++} diff --git a/gdb-6.3-pie-20050110.patch b/gdb-6.3-pie-20050110.patch new file mode 100644 index 0000000..6600d2e --- /dev/null +++ b/gdb-6.3-pie-20050110.patch @@ -0,0 +1,1441 @@ +2007-11-02 Jan Kratochvil + + Port to GDB-6.7.1. + +2007-11-02 Jan Kratochvil + + Port to post-GDB-6.7.1 multi-PC breakpoints. + +2007-11-09 Jan Kratochvil + + * solib-svr4.c (svr4_current_sos): Fix segfault on NULL EXEC_BFD. + +2008-02-24 Jan Kratochvil + + Port to GDB-6.8pre. + +2008-02-27 Jan Kratochvil + + Port to gdb-6.7.50.20080227. + +2008-06-01 Jan Kratochvil + + Fix crash on a watchpoint update on an inferior stop. + +2008-09-01 Jan Kratochvil + + Fix scan_dyntag() for binaries provided by valgrind (BZ 460319). + +Index: gdb-6.8.50.20090302/gdb/amd64-tdep.c +=================================================================== +--- gdb-6.8.50.20090302.orig/gdb/amd64-tdep.c 2009-03-07 00:30:09.000000000 +0100 ++++ gdb-6.8.50.20090302/gdb/amd64-tdep.c 2009-03-07 00:30:12.000000000 +0100 +@@ -36,6 +36,7 @@ + #include "regcache.h" + #include "regset.h" + #include "symfile.h" ++#include "exceptions.h" + + #include "gdb_assert.h" + +@@ -1586,16 +1587,28 @@ amd64_analyze_stack_align (CORE_ADDR pc, + 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; ++ } + + pc = amd64_analyze_stack_align (pc, current_pc, cache); + +@@ -1610,18 +1623,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; + } + +Index: gdb-6.8.50.20090302/gdb/auxv.c +=================================================================== +--- gdb-6.8.50.20090302.orig/gdb/auxv.c 2009-03-07 00:30:06.000000000 +0100 ++++ gdb-6.8.50.20090302/gdb/auxv.c 2009-03-07 00:30:12.000000000 +0100 +@@ -81,7 +81,7 @@ procfs_xfer_auxv (struct target_ops *ops + Return 1 if an entry was read into *TYPEP and *VALP. */ + static int + default_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 = gdbarch_ptr_bit (target_gdbarch) + / TARGET_CHAR_BIT; +@@ -108,7 +108,7 @@ default_auxv_parse (struct target_ops *o + 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) + { + struct target_ops *t; + for (t = ops; t != NULL; t = t->beneath) +@@ -123,9 +123,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; +@@ -135,10 +136,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; +@@ -161,7 +162,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); +@@ -171,13 +173,13 @@ 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) + { + 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 +@@ -232,7 +234,7 @@ fprint_target_auxv (struct ui_file *file + } + + fprintf_filtered (file, "%-4s %-20s %-30s ", +- plongest (type), name, description); ++ plongest (at_type), name, description); + switch (flavor) + { + case dec: +@@ -254,7 +256,7 @@ fprint_target_auxv (struct ui_file *file + break; + } + ++ents; +- if (type == AT_NULL) ++ if (at_type == AT_NULL) + break; + } + +Index: gdb-6.8.50.20090302/gdb/auxv.h +=================================================================== +--- gdb-6.8.50.20090302.orig/gdb/auxv.h 2009-01-03 06:57:50.000000000 +0100 ++++ gdb-6.8.50.20090302/gdb/auxv.h 2009-03-07 00:30:12.000000000 +0100 +@@ -36,14 +36,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-6.8.50.20090302/gdb/breakpoint.c +=================================================================== +--- gdb-6.8.50.20090302.orig/gdb/breakpoint.c 2009-03-07 00:30:10.000000000 +0100 ++++ gdb-6.8.50.20090302/gdb/breakpoint.c 2009-03-07 00:30:12.000000000 +0100 +@@ -3920,7 +3920,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)" +@@ -5008,6 +5009,61 @@ create_catchpoint (int tempflag, char *c + return b; + } + ++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, + struct breakpoint_ops *ops) +Index: gdb-6.8.50.20090302/gdb/breakpoint.h +=================================================================== +--- gdb-6.8.50.20090302.orig/gdb/breakpoint.h 2009-03-07 00:30:06.000000000 +0100 ++++ gdb-6.8.50.20090302/gdb/breakpoint.h 2009-03-07 00:30:12.000000000 +0100 +@@ -127,6 +127,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 +@@ -847,6 +848,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-6.8.50.20090302/gdb/dwarf2read.c +=================================================================== +--- gdb-6.8.50.20090302.orig/gdb/dwarf2read.c 2009-03-07 00:30:10.000000000 +0100 ++++ gdb-6.8.50.20090302/gdb/dwarf2read.c 2009-03-07 00:30:12.000000000 +0100 +@@ -1413,7 +1413,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-6.8.50.20090302/gdb/elfread.c +=================================================================== +--- gdb-6.8.50.20090302.orig/gdb/elfread.c 2009-03-07 00:30:06.000000000 +0100 ++++ gdb-6.8.50.20090302/gdb/elfread.c 2009-03-07 00:30:12.000000000 +0100 +@@ -680,7 +680,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-6.8.50.20090302/gdb/infrun.c +=================================================================== +--- gdb-6.8.50.20090302.orig/gdb/infrun.c 2009-03-07 00:30:10.000000000 +0100 ++++ gdb-6.8.50.20090302/gdb/infrun.c 2009-03-07 00:30:12.000000000 +0100 +@@ -3354,6 +3354,11 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME ( + #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-6.8.50.20090302/gdb/objfiles.c +=================================================================== +--- gdb-6.8.50.20090302.orig/gdb/objfiles.c 2009-03-07 00:30:06.000000000 +0100 ++++ gdb-6.8.50.20090302/gdb/objfiles.c 2009-03-07 00:30:12.000000000 +0100 +@@ -51,6 +51,9 @@ + #include "arch-utils.h" + #include "exec.h" + ++#include "auxv.h" ++#include "elf/common.h" ++ + /* Prototypes for local functions */ + + static void objfile_alloc_data (struct objfile *objfile); +@@ -271,7 +274,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. +@@ -443,6 +458,9 @@ free_objfile (struct objfile *objfile) + if (objfile == rt_common_objfile) + rt_common_objfile = NULL; + ++ if (objfile == symfile_objfile) ++ symfile_objfile = NULL; ++ + /* Before the symbol table code was redone to make it easier to + selectively load and remove information particular to a specific + linkage unit, gdb used to do these things whenever the monolithic +Index: gdb-6.8.50.20090302/gdb/solib-svr4.c +=================================================================== +--- gdb-6.8.50.20090302.orig/gdb/solib-svr4.c 2009-03-07 00:30:09.000000000 +0100 ++++ gdb-6.8.50.20090302/gdb/solib-svr4.c 2009-03-07 00:30:12.000000000 +0100 +@@ -45,6 +45,7 @@ + #include "exec.h" + #include "auxv.h" + #include "exceptions.h" ++#include "command.h" + + static struct link_map_offsets *svr4_fetch_link_map_offsets (void); + static int svr4_have_link_map_offsets (void); +@@ -287,7 +288,9 @@ static CORE_ADDR main_lm_addr; + + /* Local function prototypes */ + ++#if 0 + static int match_main (char *); ++#endif + + static CORE_ADDR bfd_lookup_symbol (bfd *, char *); + +@@ -521,10 +524,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 reloc_addr = 0; + 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; +@@ -532,19 +537,81 @@ 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) ++ { ++ 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 == 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); ++ } ++ reloc_addr = entry_addr - bfd_get_start_address (exec_bfd); ++ if (debug_solib) ++ fprintf_unfiltered (gdb_stdlog, ++ "elf_locate_base: expected relocation offset 0x%s for %s\n", ++ paddr_nz (reloc_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) +@@ -565,26 +632,105 @@ scan_dyntag (int dyntag, bfd *abfd, CORE + dyn_tag = bfd_h_get_64 (abfd, (bfd_byte *) x_dynp_64->d_tag); + dyn_ptr = bfd_h_get_64 (abfd, (bfd_byte *) x_dynp_64->d_un.d_ptr); + } +- if (dyn_tag == DT_NULL) ++ ++ /* Verify RELOC_ADDR makes sense - it does not have to for valgrind which ++ supplies us a specially crafted executable in /proc/PID/fd/X while ++ /proc/PID/auxv corresponds to a different executable (.../memcheck). */ ++ if (reloc_addr) ++ { ++ gdb_byte tag_buf[8]; ++ CORE_ADDR tag_addr; ++ ++ tag_addr = dyn_addr + (buf - bufstart) + reloc_addr; ++ if (target_read_memory (tag_addr, tag_buf, arch_size / 8) == 0) ++ { ++ if (memcmp (tag_buf, buf, arch_size / 8) != 0) ++ { ++ if (debug_solib) ++ fprintf_unfiltered (gdb_stdlog, ++ "elf_locate_base: tag at offset 0x%lx does not match," ++ " dropping relocation offset %s\n", ++ (unsigned long) (buf - bufstart), paddr_nz (reloc_addr)); ++ reloc_addr = 0; ++ } ++ } ++ else ++ { ++ if (debug_solib) ++ fprintf_unfiltered (gdb_stdlog, ++ "elf_locate_base: tag at offset 0x%lx is not readable," ++ " dropping relocation offset %s\n", ++ (unsigned long) (buf - bufstart), paddr_nz (reloc_addr)); ++ reloc_addr = 0; ++ } ++ } ++ ++ if (dyn_tag == DT_NULL) + return 0; +- if (dyn_tag == dyntag) +- { +- /* If requested, try to read the runtime value of this .dynamic +- entry. */ +- if (ptr) +- { +- struct type *ptr_type; +- gdb_byte ptr_buf[8]; +- CORE_ADDR ptr_addr; +- +- ptr_type = builtin_type (target_gdbarch)->builtin_data_ptr; +- ptr_addr = dyn_addr + (buf - bufstart) + arch_size / 8; +- if (target_read_memory (ptr_addr, ptr_buf, arch_size / 8) == 0) +- dyn_ptr = extract_typed_address (ptr_buf, ptr_type); +- *ptr = dyn_ptr; +- } +- return 1; +- } ++ if (dyn_tag == dyntag) ++ { ++ /* If requested, try to read the runtime value of this .dynamic ++ entry. */ ++ if (ptr) ++ { ++ gdb_byte ptr_buf[8]; ++ CORE_ADDR ptr_addr; ++ int got; ++ ++ 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 += reloc_addr; ++ if (debug_solib) ++ fprintf_unfiltered (gdb_stdlog, ++ "elf_locate_base: relocated ptr addr 0x%s" ++ " (relocation offset %s) for %s\n", ++ paddr_nz (ptr_addr), paddr_nz (reloc_addr), ++ exec_bfd->filename); ++ } ++ got = target_read_memory (ptr_addr, ptr_buf, arch_size / 8); ++ if (got != 0 && reloc_addr) ++ { ++ ptr_addr -= reloc_addr; ++ if (debug_solib) ++ fprintf_unfiltered (gdb_stdlog, ++ "elf_locate_base: unrelocated back to ptr addr 0x%s" ++ " as the memory was unreable for %s\n", ++ paddr_nz (ptr_addr), exec_bfd->filename); ++ got = target_read_memory (ptr_addr, ptr_buf, arch_size / 8); ++ } ++ ++ if (got == 0) ++ { ++ struct type *ptr_type; ++ ++ ptr_type = builtin_type (target_gdbarch)->builtin_data_ptr; ++ dyn_ptr = extract_typed_address (ptr_buf, ptr_type); ++ 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; ++ } + } + + return 0; +@@ -774,6 +920,10 @@ solib_svr4_r_map (void) + struct link_map_offsets *lmo = svr4_fetch_link_map_offsets (); + struct type *ptr_type = builtin_type (target_gdbarch)->builtin_data_ptr; + ++ 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, ptr_type); + } + +@@ -945,6 +1095,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 : ""; ++ ++ 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; +@@ -953,10 +1108,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) +@@ -973,26 +1137,104 @@ 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) ++ if (exec_bfd != NULL && IGNORE_FIRST_LINK_MAP_ENTRY (new) && ldsomap == 0) + { +- main_lm_addr = new->lm_info->lm_addr; +- free_so (new); +- } ++ /* 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. */ ++ main_lm_addr = new->lm_info->lm_addr; ++ 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) +@@ -1000,47 +1242,60 @@ svr4_current_sos (void) + safe_strerror (errcode)); + else + { +- struct build_id *build_id; ++ 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 ++ { ++ struct build_id *build_id; + +- strncpy (new->so_original_name, buffer, SO_NAME_MAX_PATH_SIZE - 1); +- new->so_original_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0'; +- /* May get overwritten below. */ +- strcpy (new->so_name, new->so_original_name); ++ strncpy (new->so_original_name, buffer, SO_NAME_MAX_PATH_SIZE - 1); ++ new->so_original_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0'; ++ /* May get overwritten below. */ ++ strcpy (new->so_name, new->so_original_name); + +- build_id = build_id_addr_get (LM_DYNAMIC_FROM_LINK_MAP (new)); +- if (build_id != NULL) +- { +- char *name, *build_id_filename; ++ build_id = build_id_addr_get (LM_DYNAMIC_FROM_LINK_MAP (new)); ++ if (build_id != NULL) ++ { ++ char *name, *build_id_filename; ++ ++ /* Missing the build-id matching separate debug info file ++ would be handled while SO_NAME gets loaded. */ ++ name = build_id_to_filename (build_id, &build_id_filename, 0); ++ if (name != NULL) ++ { ++ strncpy (new->so_name, name, SO_NAME_MAX_PATH_SIZE - 1); ++ new->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0'; ++ xfree (name); ++ } ++ else ++ debug_print_missing (new->so_name, build_id_filename); ++ ++ xfree (build_id_filename); ++ xfree (build_id); ++ } + +- /* Missing the build-id matching separate debug info file +- would be handled while SO_NAME gets loaded. */ +- name = build_id_to_filename (build_id, &build_id_filename, 0); +- if (name != NULL) ++ if (debug_solib) + { +- strncpy (new->so_name, name, SO_NAME_MAX_PATH_SIZE - 1); +- new->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0'; +- xfree (name); ++ 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)); + } +- else +- debug_print_missing (new->so_name, build_id_filename); + +- xfree (build_id_filename); +- xfree (build_id); ++ new->next = 0; ++ *link_ptr = new; ++ link_ptr = &new->next; + } + } +- 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; +- } ++ xfree (buffer); + } + + /* On Solaris, the dynamic linker is not in the normal list of +@@ -1056,6 +1311,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; + } + +@@ -1087,7 +1345,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) + { +@@ -1101,6 +1359,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. */ +@@ -1251,15 +1510,29 @@ enable_break (void) + /* Find the program interpreter; if not found, warn the user and drop + into the old breakpoint at symbol code. */ + interp_name = find_program_interpreter (); ++ ++ if (debug_solib) ++ fprintf_unfiltered (gdb_stdlog, ++ "enable_break: search for .interp in %s\n", ++ exec_bfd->filename); + if (interp_name) + { + CORE_ADDR load_addr = 0; ++ CORE_ADDR load_addr_mask = -1L; + int load_addr_found = 0; + int loader_found_in_list = 0; + struct so_list *so; + bfd *tmp_bfd = NULL; + struct target_ops *tmp_bfd_target; + volatile struct gdb_exception ex; ++ int arch_size; ++ ++ /* For 32bit inferiors with 64bit GDB we may get LOAD_ADDR at 0xff...... ++ and thus overflowing its addition to the address while CORE_ADDR is ++ 64bit producing 0x1........ address invalid across GDB. */ ++ arch_size = bfd_get_arch_size (exec_bfd); ++ if (arch_size > 0 && arch_size < sizeof (1UL) * 8) ++ load_addr_mask = (1UL << arch_size) - 1; + + sym_addr = 0; + +@@ -1276,6 +1549,9 @@ enable_break (void) + { + tmp_bfd = solib_bfd_open (interp_name); + } ++ if (debug_solib) ++ fprintf_unfiltered (gdb_stdlog, ++ "enable_break: opening %s\n", interp_name); + if (tmp_bfd == NULL) + goto bkpt_at_symbol; + +@@ -1329,16 +1605,16 @@ enable_break (void) + interp_sect = bfd_get_section_by_name (tmp_bfd, ".text"); + if (interp_sect) + { +- interp_text_sect_low = +- bfd_section_vma (tmp_bfd, interp_sect) + load_addr; ++ interp_text_sect_low = (bfd_section_vma (tmp_bfd, interp_sect) ++ + load_addr) & load_addr_mask; + interp_text_sect_high = + interp_text_sect_low + bfd_section_size (tmp_bfd, interp_sect); + } + interp_sect = bfd_get_section_by_name (tmp_bfd, ".plt"); + if (interp_sect) + { +- interp_plt_sect_low = +- bfd_section_vma (tmp_bfd, interp_sect) + load_addr; ++ interp_plt_sect_low = (bfd_section_vma (tmp_bfd, interp_sect) ++ + load_addr) & load_addr_mask; + interp_plt_sect_high = + interp_plt_sect_low + bfd_section_size (tmp_bfd, interp_sect); + } +@@ -1373,7 +1649,11 @@ enable_break (void) + + if (sym_addr != 0) + { +- create_solib_event_breakpoint (load_addr + sym_addr); ++ create_solib_event_breakpoint ((load_addr + sym_addr) ++ & load_addr_mask); ++ if (debug_solib) ++ fprintf_unfiltered (gdb_stdlog, ++ "enable_break: solib bp set\n"); + xfree (interp_name); + return 1; + } +@@ -1639,6 +1919,8 @@ svr4_solib_create_inferior_hook (void) + while (tp->stop_signal != TARGET_SIGNAL_TRAP); + inf->stop_soon = NO_STOP_QUIETLY; + #endif /* defined(_SCO_DS) */ ++ ++ disable_breakpoints_at_startup (1); + } + + static void +@@ -1820,6 +2102,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; +@@ -1859,4 +2210,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-6.8.50.20090302/gdb/solib.c +=================================================================== +--- gdb-6.8.50.20090302.orig/gdb/solib.c 2009-02-21 17:14:49.000000000 +0100 ++++ gdb-6.8.50.20090302/gdb/solib.c 2009-03-07 00:30:12.000000000 +0100 +@@ -81,6 +81,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; +@@ -104,6 +106,8 @@ The search path for loading non-absolute + value); + } + ++void add_to_target_sections (int, struct target_ops *, struct so_list *); ++ + /* + + GLOBAL FUNCTION +@@ -426,10 +430,23 @@ free_so (struct so_list *so) + + if (so->abfd) + { +- bfd_filename = bfd_get_filename (so->abfd); +- if (! bfd_close (so->abfd)) +- warning (_("cannot close \"%s\": %s"), +- bfd_filename, bfd_errmsg (bfd_get_error ())); ++ struct objfile *objfile; ++ ++ ALL_OBJFILES (objfile) ++ if (objfile->obfd == so->abfd) ++ { ++ gdb_assert (objfile->flags & OBJF_KEEPBFD); ++ objfile->flags &= ~OBJF_KEEPBFD; ++ break; ++ } ++ ++ if (!objfile) ++ { ++ bfd_filename = bfd_get_filename (so->abfd); ++ if (! bfd_close (so->abfd)) ++ warning (_("cannot close \"%s\": %s"), ++ bfd_filename, bfd_errmsg (bfd_get_error ())); ++ } + } + + if (bfd_filename) +@@ -460,15 +477,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_from_bfd (so->abfd, so->from_tty, +- sap, 0, OBJF_SHARED | OBJF_KEEPBFD); ++ if (so->main) ++ { ++ if (debug_solib) ++ fprintf_unfiltered (gdb_stdlog, ++ "symbol_add_stub: adding symbols for main\n"); ++ so->objfile = symbol_file_add_from_bfd (so->abfd, /*so->from_tty*/ 0, ++ sap, 1, OBJF_KEEPBFD); ++ so->main_relocated = 1; ++ } ++ else ++ so->objfile = symbol_file_add_from_bfd (so->abfd, so->from_tty, ++ sap, 0, OBJF_SHARED | OBJF_KEEPBFD); ++ + free_section_addr_info (sap); + + return (1); +@@ -600,6 +642,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; + } +@@ -654,28 +700,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. */ +@@ -771,6 +796,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])); ++ } ++ } ++} + + /* + +@@ -1089,4 +1149,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-6.8.50.20090302/gdb/solist.h +=================================================================== +--- gdb-6.8.50.20090302.orig/gdb/solist.h 2009-02-04 09:42:11.000000000 +0100 ++++ gdb-6.8.50.20090302/gdb/solist.h 2009-03-07 00:30:12.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; +@@ -149,4 +151,10 @@ struct symbol *solib_global_lookup (cons + const char *linkage_name, + const domain_enum domain); + ++/* 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 *); ++ ++/* Controls the printing of debugging output. */ ++extern int debug_solib; ++ + #endif +Index: gdb-6.8.50.20090302/gdb/symfile-mem.c +=================================================================== +--- gdb-6.8.50.20090302.orig/gdb/symfile-mem.c 2009-03-07 00:30:08.000000000 +0100 ++++ gdb-6.8.50.20090302/gdb/symfile-mem.c 2009-03-07 00:30:12.000000000 +0100 +@@ -116,7 +116,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-6.8.50.20090302/gdb/symfile.c +=================================================================== +--- gdb-6.8.50.20090302.orig/gdb/symfile.c 2009-03-07 00:30:09.000000000 +0100 ++++ gdb-6.8.50.20090302/gdb/symfile.c 2009-03-07 00:31:24.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" +@@ -787,7 +788,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. */ +@@ -815,7 +816,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; +@@ -917,17 +918,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); +@@ -980,7 +985,7 @@ symbol_file_add_with_addrs_or_offsets (b + /* Give user a chance to burp if we'd be + interactively wiping out any existing symbols. */ + +- if (mainline ++ if (mainline == 1 + && from_tty + && (have_full_symbols () || have_partial_symbols ()) + && !query (_("Load new symbol table from \"%s\"? "), name)) +@@ -1175,6 +1180,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 +@@ -3275,6 +3284,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. */ +Index: gdb-6.8.50.20090302/gdb/target.h +=================================================================== +--- gdb-6.8.50.20090302.orig/gdb/target.h 2009-03-07 00:30:09.000000000 +0100 ++++ gdb-6.8.50.20090302/gdb/target.h 2009-03-07 00:30:12.000000000 +0100 +@@ -542,7 +542,7 @@ struct target_ops + Return -1 if there is insufficient buffer for a whole entry. + Return 1 if an entry was read into *TYPEP and *VALP. */ + int (*to_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); + + /* Search SEARCH_SPACE_LEN bytes beginning at START_ADDR for the + sequence of bytes in PATTERN with length PATTERN_LEN. diff --git a/gdb-6.3-ppc64displaysymbol-20041124.patch b/gdb-6.3-ppc64displaysymbol-20041124.patch new file mode 100644 index 0000000..8e94e00 --- /dev/null +++ b/gdb-6.3-ppc64displaysymbol-20041124.patch @@ -0,0 +1,24 @@ +2004-11-24 Andrew Cagney + + * printcmd.c (build_address_symbolic): Find a section for the + address. + +Index: gdb-6.8.50.20081128/gdb/printcmd.c +=================================================================== +--- gdb-6.8.50.20081128.orig/gdb/printcmd.c 2008-12-04 01:36:05.000000000 +0100 ++++ gdb-6.8.50.20081128/gdb/printcmd.c 2008-12-04 01:37:18.000000000 +0100 +@@ -616,6 +616,14 @@ build_address_symbolic (CORE_ADDR addr, + addr = overlay_mapped_address (addr, section); + } + } ++ /* To ensure that the symbol returned belongs to the correct setion ++ (and that the last [random] symbol from the previous section ++ isn't returned) try to find the section containing PC. First try ++ the overlay code (which by default returns NULL); and second try ++ the normal section code (which almost always succeeds). */ ++ section = find_pc_overlay (addr); ++ if (section == NULL) ++ section = find_pc_section (addr); + + /* First try to find the address in the symbol table, then + in the minsyms. Take the closest one. */ diff --git a/gdb-6.3-ppc64syscall-20040622.patch b/gdb-6.3-ppc64syscall-20040622.patch new file mode 100644 index 0000000..99529db --- /dev/null +++ b/gdb-6.3-ppc64syscall-20040622.patch @@ -0,0 +1,110 @@ +2004-06-22 Andrew Cagney + + * rs6000-tdep.c (struct rs6000_framedata): Add field "func_start". + (skip_prologue): Delete local variable "orig_pc", use + "func_start". Add local variable "num_skip_linux_syscall_insn", + use to skip over first half of a GNU/Linux syscall and update + "func_start". + +Index: gdb-6.8/gdb/rs6000-tdep.c +=================================================================== +--- gdb-6.8.orig/gdb/rs6000-tdep.c 2008-02-20 15:34:43.000000000 +0100 ++++ gdb-6.8/gdb/rs6000-tdep.c 2008-07-14 10:25:29.000000000 +0200 +@@ -124,6 +124,7 @@ static const char *powerpc_vector_abi_st + + struct rs6000_framedata + { ++ CORE_ADDR func_start; /* True function start. */ + int offset; /* total size of frame --- the distance + by which we decrement sp to allocate + the frame */ +@@ -1262,7 +1263,6 @@ static CORE_ADDR + skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc, + struct rs6000_framedata *fdata) + { +- CORE_ADDR orig_pc = pc; + CORE_ADDR last_prologue_pc = pc; + CORE_ADDR li_found_pc = 0; + gdb_byte buf[4]; +@@ -1280,11 +1280,13 @@ skip_prologue (struct gdbarch *gdbarch, + int minimal_toc_loaded = 0; + int prev_insn_was_prologue_insn = 1; + int num_skip_non_prologue_insns = 0; ++ int num_skip_ppc64_gnu_linux_syscall_insn = 0; + int r0_contains_arg = 0; + const struct bfd_arch_info *arch_info = gdbarch_bfd_arch_info (gdbarch); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + memset (fdata, 0, sizeof (struct rs6000_framedata)); ++ fdata->func_start = pc; + fdata->saved_gpr = -1; + fdata->saved_fpr = -1; + fdata->saved_vr = -1; +@@ -1313,6 +1315,55 @@ skip_prologue (struct gdbarch *gdbarch, + break; + op = extract_unsigned_integer (buf, 4); + ++ /* A PPC64 GNU/Linux system call function is split into two ++ sub-functions: a non-threaded fast-path (__NAME_nocancel) ++ which does not use a frame; and a threaded slow-path ++ (Lpseudo_cancel) that does create a frame. Ref: ++ nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h ++ ++ *INDENT-OFF* ++ NAME: ++ SINGLE_THREAD_P ++ bne- .Lpseudo_cancel ++ __NAME_nocancel: ++ li r0,162 ++ sc ++ bnslr+ ++ b 0x7fe014ef64 <.__syscall_error> ++ Lpseudo_cancel: ++ stdu r1,-128(r1) ++ ... ++ *INDENT-ON* ++ ++ Unfortunatly, because the latter case uses a local label (not ++ in the symbol table) a PC in "Lpseudo_cancel" appears to be ++ in "__NAME_nocancel". The following code recognizes this, ++ adjusting FUNC_START to point to where "Lpseudo_cancel" ++ should be, and parsing the prologue sequence as if ++ "Lpseudo_cancel" was the entry point. */ ++ ++ if (((op & 0xffff0000) == 0x38000000 /* li r0,N */ ++ && pc == fdata->func_start + 0 ++ && num_skip_ppc64_gnu_linux_syscall_insn == 0) ++ || (op == 0x44000002 /* sc */ ++ && pc == fdata->func_start + 4 ++ && num_skip_ppc64_gnu_linux_syscall_insn == 1) ++ || (op == 0x4ca30020 /* bnslr+ */ ++ && pc == fdata->func_start + 8 ++ && num_skip_ppc64_gnu_linux_syscall_insn == 2)) ++ { ++ num_skip_ppc64_gnu_linux_syscall_insn++; ++ continue; ++ } ++ else if ((op & 0xfc000003) == 0x48000000 /* b __syscall_error */ ++ && pc == fdata->func_start + 12 ++ && num_skip_ppc64_gnu_linux_syscall_insn == 3) ++ { ++ num_skip_ppc64_gnu_linux_syscall_insn = -1; ++ fdata->func_start = pc; ++ continue; ++ } ++ + if ((op & 0xfc1fffff) == 0x7c0802a6) + { /* mflr Rx */ + /* Since shared library / PIC code, which needs to get its +@@ -1486,9 +1537,9 @@ skip_prologue (struct gdbarch *gdbarch, + we have no line table information or the line info tells + us that the subroutine call is not part of the line + associated with the prologue. */ +- if ((pc - orig_pc) > 8) ++ if ((pc - fdata->func_start) > 8) + { +- struct symtab_and_line prologue_sal = find_pc_line (orig_pc, 0); ++ struct symtab_and_line prologue_sal = find_pc_line (fdata->func_start, 0); + struct symtab_and_line this_sal = find_pc_line (pc, 0); + + if ((prologue_sal.line == 0) || (prologue_sal.line != this_sal.line)) diff --git a/gdb-6.3-ppcdotsolib-20041022.patch b/gdb-6.3-ppcdotsolib-20041022.patch new file mode 100644 index 0000000..046633e --- /dev/null +++ b/gdb-6.3-ppcdotsolib-20041022.patch @@ -0,0 +1,31 @@ +2004-10-22 Andrew Cagney + + * solib-svr4.c (enable_break): Convert a symbol descriptor into + the corresponding function entry point. + (solib_break_names): Delete "._dl_debug_state", no longer needed. + +2007-10-12 Jan Kratochvil + + Port to GDB-6.7. + +Index: gdb-6.7/gdb/solib-svr4.c +=================================================================== +--- gdb-6.7.orig/gdb/solib-svr4.c 2007-10-09 20:03:30.000000000 +0200 ++++ gdb-6.7/gdb/solib-svr4.c 2007-10-12 22:34:03.000000000 +0200 +@@ -1089,7 +1089,15 @@ enable_break (void) + { + sym_addr = bfd_lookup_symbol (tmp_bfd, *bkpt_namep); + if (sym_addr != 0) +- break; ++ { ++ /* The symbol might be a descriptor, convert to into the ++ corresponding code address. */ ++ sym_addr = gdbarch_convert_from_func_ptr_addr (current_gdbarch, ++ sym_addr, ++ tmp_bfd_target); ++ if (sym_addr != 0) ++ break; ++ } + } + + if (sym_addr != 0) diff --git a/gdb-6.3-readnever-20050907.patch b/gdb-6.3-readnever-20050907.patch new file mode 100644 index 0000000..ab645b4 --- /dev/null +++ b/gdb-6.3-readnever-20050907.patch @@ -0,0 +1,96 @@ +2004-11-18 Andrew Cagney + + * dwarf2read.c: Include "top.c". + (dwarf2_has_info): Check for readnever_symbol_files. + * symfile.c (readnever_symbol_files): Define. + * top.h (readnever_symbol_files): Declare. + * main.c (captured_main): Add --readnever option. + (print_gdb_help): Ditto. + +2004-11-18 Andrew Cagney + + * gdb.texinfo (File Options): Document --readnever. + +Index: gdb-6.8.50.20090228/gdb/doc/gdb.texinfo +=================================================================== +--- gdb-6.8.50.20090228.orig/gdb/doc/gdb.texinfo 2009-03-02 01:01:15.000000000 +0100 ++++ gdb-6.8.50.20090228/gdb/doc/gdb.texinfo 2009-03-02 01:01:23.000000000 +0100 +@@ -988,6 +988,12 @@ Read each symbol file's entire symbol ta + the default, which is to read it incrementally as it is needed. + This makes startup slower, but makes future operations faster. + ++@item --readnever ++@cindex @code{--readnever} ++Do not read each symbol file's symbolic debug information. This makes ++startup faster but at the expense of not being able to perform ++symbolic debugging. ++ + @end table + + @node Mode Options +Index: gdb-6.8.50.20090228/gdb/main.c +=================================================================== +--- gdb-6.8.50.20090228.orig/gdb/main.c 2009-03-02 01:01:17.000000000 +0100 ++++ gdb-6.8.50.20090228/gdb/main.c 2009-03-02 01:01:23.000000000 +0100 +@@ -427,6 +427,7 @@ captured_main (void *data) + {"xdb", no_argument, &xdb_commands, 1}, + {"dbx", no_argument, &dbx_commands, 1}, + {"readnow", no_argument, &readnow_symbol_files, 1}, ++ {"readnever", no_argument, &readnever_symbol_files, 1}, + {"r", no_argument, &readnow_symbol_files, 1}, + {"quiet", no_argument, &quiet, 1}, + {"q", no_argument, &quiet, 1}, +@@ -1070,6 +1071,7 @@ Options:\n\n\ + fputs_unfiltered (_("\ + --quiet Do not print version number on startup.\n\ + --readnow Fully read symbol files on first access.\n\ ++ --readnever Do not read symbol files.\n\ + "), stream); + fputs_unfiltered (_("\ + --se=FILE Use FILE as symbol file and executable file.\n\ +Index: gdb-6.8.50.20090228/gdb/symfile.c +=================================================================== +--- gdb-6.8.50.20090228.orig/gdb/symfile.c 2009-03-02 01:01:17.000000000 +0100 ++++ gdb-6.8.50.20090228/gdb/symfile.c 2009-03-02 01:01:23.000000000 +0100 +@@ -77,6 +77,7 @@ static void clear_symtab_users_cleanup ( + + /* Global variables owned by this file */ + int readnow_symbol_files; /* Read full symbols immediately */ ++int readnever_symbol_files; /* Never read full symbols. */ + + /* External variables and functions referenced. */ + +Index: gdb-6.8.50.20090228/gdb/dwarf2read.c +=================================================================== +--- gdb-6.8.50.20090228.orig/gdb/dwarf2read.c 2009-03-02 01:01:15.000000000 +0100 ++++ gdb-6.8.50.20090228/gdb/dwarf2read.c 2009-03-02 01:01:36.000000000 +0100 +@@ -49,6 +49,7 @@ + #include "f-lang.h" + #include "c-lang.h" + #include "typeprint.h" ++#include "top.h" + + #include + #include "gdb_string.h" +@@ -1161,7 +1162,8 @@ dwarf2_has_info (struct objfile *objfile + dwarf_aranges_section = 0; + + bfd_map_over_sections (objfile->obfd, dwarf2_locate_sections, &update_sizes); +- return (dwarf_info_section != NULL && dwarf_abbrev_section != NULL); ++ return !readnever_symbol_files ++ && dwarf_info_section != NULL && dwarf_abbrev_section != NULL; + } + + /* When loading sections, we can either look for ".", or for +Index: gdb-6.8.50.20090228/gdb/top.h +=================================================================== +--- gdb-6.8.50.20090228.orig/gdb/top.h 2009-01-03 06:57:53.000000000 +0100 ++++ gdb-6.8.50.20090228/gdb/top.h 2009-03-02 01:01:23.000000000 +0100 +@@ -59,6 +59,7 @@ extern void set_prompt (char *); + + /* From random places. */ + extern int readnow_symbol_files; ++extern int readnever_symbol_files; + + /* Perform _initialize initialization */ + extern void gdb_init (char *); diff --git a/gdb-6.3-removebp-20041130.patch b/gdb-6.3-removebp-20041130.patch new file mode 100644 index 0000000..093b3c2 --- /dev/null +++ b/gdb-6.3-removebp-20041130.patch @@ -0,0 +1,29 @@ +2004-11-30 Jeff Johnston + + * breakpoint.c (remove_breakpoints): Continue removing breakpoints + even if an error occurs. Remove a failure code for the last failure + only. + +--- gdb+dejagnu-20040607/gdb/breakpoint.c.fix2 Tue Nov 30 18:01:33 2004 ++++ gdb+dejagnu-20040607/gdb/breakpoint.c Tue Nov 30 18:06:01 2004 +@@ -1297,6 +1297,7 @@ remove_breakpoints (void) + { + struct bp_location *b; + int val; ++ int return_val = 0; + + ALL_BP_LOCATIONS (b) + { +@@ -1304,10 +1305,10 @@ remove_breakpoints (void) + { + val = remove_breakpoint (b, mark_uninserted); + if (val != 0) +- return val; ++ return_val = val; + } + } +- return 0; ++ return return_val; + } + + int diff --git a/gdb-6.3-rh-dummykfail-20041202.patch b/gdb-6.3-rh-dummykfail-20041202.patch new file mode 100644 index 0000000..1f0bc9d --- /dev/null +++ b/gdb-6.3-rh-dummykfail-20041202.patch @@ -0,0 +1,22 @@ +2003-07-11 Elena Zannoni + + * lib/gdb.exp (setup_kfail, kfail): Redefine procedures. + +--- ./gdb/testsuite/lib/gdb.exp.1 2004-11-24 15:59:46.131394720 -0500 ++++ ./gdb/testsuite/lib/gdb.exp 2004-11-24 16:01:06.304206600 -0500 +@@ -63,6 +63,15 @@ + + ### Only procedures should come after this point. + ++if {![llength [info procs kfail]]} { ++ proc setup_kfail { args } { ++ #setup_xfail args ++ } ++ proc kfail { bugid message } { ++ fail $message ++ } ++} ++ + # + # gdb_version -- extract and print the version number of GDB + # diff --git a/gdb-6.3-rh-testlibunwind-20041202.patch b/gdb-6.3-rh-testlibunwind-20041202.patch new file mode 100644 index 0000000..5c23804 --- /dev/null +++ b/gdb-6.3-rh-testlibunwind-20041202.patch @@ -0,0 +1,76 @@ +2003-11-17 Elena Zannoni + + From Jeff Johnston + * gdb.arch/ia64-libunwind.exp: New file. + * gdb.arch/ia64-libunwind.c: New file. + +--- /dev/null Thu Apr 11 10:25:15 2002 ++++ gdb+dejagnu-20040223/gdb/testsuite/gdb.arch/ia64-libunwind.exp Mon Nov 17 15:57:04 2003 +@@ -0,0 +1,55 @@ ++# Copyright 2003 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++# Please email any bugs, comments, and/or additions to this file to: ++# bug-gdb@prep.ai.mit.edu ++ ++# This file was written by Jeff Johnston (jjohnstn@redhat.com) ++ ++if $tracelevel then { ++ strace $tracelevel ++} ++ ++# ++# test running programs ++# ++set prms_id 0 ++set bug_id 0 ++ ++if ![istarget "ia64-*-*"] then { ++ return ++} ++ ++set testfile "ia64-libunwind" ++set srcfile ${testfile}.c ++set binfile ${objdir}/${subdir}/${testfile} ++ ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug additional_flags=-w}] != "" } { ++ gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail." ++} ++ ++if [get_compiler_info ${binfile}] { ++ return -1 ++} ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++send_gdb "set debug arch 1\n" ++send_gdb "break main\n" ++gdb_test "run" ".*acquire_unwind_info.*" ++ +--- /dev/null Thu Apr 11 10:25:15 2002 ++++ gdb+dejagnu-20040223/gdb/testsuite/gdb.arch/ia64-libunwind.c Mon Nov 17 15:58:27 2003 +@@ -0,0 +1,9 @@ ++#include ++ ++int main() ++{ ++ printf ("hello world\n"); ++ ++ return 0; ++} ++ diff --git a/gdb-6.3-rh-testlibunwind1fix-20041202.patch b/gdb-6.3-rh-testlibunwind1fix-20041202.patch new file mode 100644 index 0000000..a30617c --- /dev/null +++ b/gdb-6.3-rh-testlibunwind1fix-20041202.patch @@ -0,0 +1,14 @@ +2004-08-03 Jeff Johnston + + * gdb.arch/ia64-libunwind.exp: Fix test string to match + current code base. + +--- gdb+dejagnu-20040607/gdb/testsuite/gdb.arch/ia64-libunwind.exp.fix Tue Aug 3 18:29:22 2004 ++++ gdb+dejagnu-20040607/gdb/testsuite/gdb.arch/ia64-libunwind.exp Tue Aug 3 18:41:01 2004 +@@ -51,5 +51,5 @@ gdb_reinitialize_dir $srcdir/$subdir + gdb_load ${binfile} + send_gdb "set debug arch 1\n" + send_gdb "break main\n" +-gdb_test "run" ".*acquire_unwind_info.*" ++gdb_test "run" ".*ia64_find_proc_info_x.*" + diff --git a/gdb-6.3-rh-testversion-20041202.patch b/gdb-6.3-rh-testversion-20041202.patch new file mode 100644 index 0000000..cf25bcd --- /dev/null +++ b/gdb-6.3-rh-testversion-20041202.patch @@ -0,0 +1,19 @@ +2003-02-24 Elena Zannoni + + * gdb.gdb/selftest.exp: Add matching on specific Red Hat only version + string. + +Index: gdb-6.8/gdb/testsuite/gdb.gdb/selftest.exp +=================================================================== +--- gdb-6.8.orig/gdb/testsuite/gdb.gdb/selftest.exp 2008-01-26 14:56:37.000000000 +0100 ++++ gdb-6.8/gdb/testsuite/gdb.gdb/selftest.exp 2008-07-14 10:23:50.000000000 +0200 +@@ -354,6 +354,9 @@ proc test_with_self { executable } { + -re ".\[0-9\]+ = +.+ +0x.*\[0-9.\]+.*$gdb_prompt $" { + pass "printed version with cast" + } ++ -re ".\[0-9\]+ = .Fedora \[\\(\\)0-9.a-z\\-\]+.*$gdb_prompt $" { ++ pass "printed version Fedora only" ++ } + -re ".*$gdb_prompt $" { fail "printed version" } + timeout { fail "(timeout) printed version" } + } diff --git a/gdb-6.3-security-errata-20050610.patch b/gdb-6.3-security-errata-20050610.patch new file mode 100644 index 0000000..1092c31 --- /dev/null +++ b/gdb-6.3-security-errata-20050610.patch @@ -0,0 +1,211 @@ +http://sourceware.org/ml/gdb-patches/2005-05/threads.html#00637 +Proposed upstream but never committed upstream. + +2005-06-09 Jeff Johnston + + * gdb.base/gdbinit.exp: New testcase. + * gdb.base/gdbinit.sample: Sample .gdbinit for gdbinit.exp. + +2005-06-08 Daniel Jacobowitz + Jeff Johnston + + * Makefile.in (cli-cmds.o): Update. + * configure.in: Add check for getuid. + * configure: Regenerated. + * config.in: Ditto. + * main.c (captured_main): Pass -1 to source_command when loading + gdbinit files. + * cli/cli-cmds.c: Include "gdb_stat.h" and . + (source_command): Update documentation. Check permissions if + FROM_TTY is -1. + +Index: gdb-6.8.50.20090226/gdb/cli/cli-cmds.c +=================================================================== +--- gdb-6.8.50.20090226.orig/gdb/cli/cli-cmds.c 2009-02-27 00:04:32.000000000 +0100 ++++ gdb-6.8.50.20090226/gdb/cli/cli-cmds.c 2009-02-28 07:17:49.000000000 +0100 +@@ -36,6 +36,7 @@ + #include "objfiles.h" + #include "source.h" + #include "disasm.h" ++#include "gdb_stat.h" + + #include "ui-out.h" + +@@ -466,7 +467,7 @@ source_script (char *file, int from_tty) + + if (fd == -1) + { +- if (from_tty) ++ if (from_tty > 0) + perror_with_name (file); + else + { +@@ -475,6 +476,29 @@ source_script (char *file, int from_tty) + } + } + ++#ifdef HAVE_GETUID ++ if (from_tty == -1) ++ { ++ struct stat statbuf; ++ ++ if (fstat (fd, &statbuf) < 0) ++ { ++ close (fd); ++ /* Do not do_cleanups (old_cleanups) as FILE is allocated there. ++ perror_with_name calls error which should call the cleanups. */ ++ perror_with_name (file); ++ } ++ if (statbuf.st_uid != getuid () || (statbuf.st_mode & S_IWOTH)) ++ { ++ /* FILE gets freed by do_cleanups (old_cleanups). */ ++ warning (_("not using untrusted file \"%s\""), file); ++ close (fd); ++ do_cleanups (old_cleanups); ++ return; ++ } ++ } ++#endif ++ + is_python = source_python; + if (strlen (file) > 3 && !strcmp (&file[strlen (file) - 3], ".py")) + is_python = 1; +@@ -486,6 +510,7 @@ source_script (char *file, int from_tty) + else + script_from_file (stream, file); + ++ /* FILE gets freed by do_cleanups (old_cleanups). */ + do_cleanups (old_cleanups); + } + +Index: gdb-6.8.50.20090226/gdb/testsuite/gdb.base/gdbinit.exp +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8.50.20090226/gdb/testsuite/gdb.base/gdbinit.exp 2009-02-28 07:15:57.000000000 +0100 +@@ -0,0 +1,98 @@ ++# Copyright 2005 ++# Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++# Please email any bugs, comments, and/or additions to this file to: ++# bug-gdb@prep.ai.mit.edu ++ ++# This file was written by Jeff Johnston . ++ ++if $tracelevel then { ++ strace $tracelevel ++} ++ ++set prms_id 0 ++set bug_id 0 ++ ++# are we on a target board ++if [is_remote target] { ++ return ++} ++ ++ ++global verbose ++global GDB ++global GDBFLAGS ++global gdb_prompt ++global timeout ++global gdb_spawn_id; ++ ++gdb_stop_suppressing_tests; ++ ++verbose "Spawning $GDB -nw" ++ ++if [info exists gdb_spawn_id] { ++ return 0; ++} ++ ++if ![is_remote host] { ++ if { [which $GDB] == 0 } then { ++ perror "$GDB does not exist." ++ exit 1 ++ } ++} ++ ++set env(HOME) [pwd] ++remote_exec build "rm .gdbinit" ++remote_exec build "cp ${srcdir}/${subdir}/gdbinit.sample .gdbinit" ++remote_exec build "chmod 646 .gdbinit" ++ ++set res [remote_spawn host "$GDB -nw [host_info gdb_opts]"]; ++if { $res < 0 || $res == "" } { ++ perror "Spawning $GDB failed." ++ return 1; ++} ++gdb_expect 360 { ++ -re "warning: not using untrusted file.*\.gdbinit.*\[\r\n\]$gdb_prompt $" { ++ pass "untrusted .gdbinit caught." ++ } ++ -re "$gdb_prompt $" { ++ fail "untrusted .gdbinit caught." ++ } ++ timeout { ++ fail "(timeout) untrusted .gdbinit caught." ++ } ++} ++ ++remote_exec build "chmod 644 .gdbinit" ++set res [remote_spawn host "$GDB -nw [host_info gdb_opts]"]; ++if { $res < 0 || $res == "" } { ++ perror "Spawning $GDB failed." ++ return 1; ++} ++gdb_expect 360 { ++ -re "warning: not using untrusted file.*\.gdbinit.*\[\r\n\]$gdb_prompt $" { ++ fail "trusted .gdbinit allowed." ++ } ++ -re "in gdbinit.*$gdb_prompt $" { ++ pass "trusted .gdbinit allowed." ++ } ++ timeout { ++ fail "(timeout) trusted .gdbinit allowed." ++ } ++} ++ ++remote_exec build "rm .gdbinit" +Index: gdb-6.8.50.20090226/gdb/testsuite/gdb.base/gdbinit.sample +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8.50.20090226/gdb/testsuite/gdb.base/gdbinit.sample 2009-02-28 07:15:57.000000000 +0100 +@@ -0,0 +1 @@ ++echo "\nin gdbinit" +Index: gdb-6.8.50.20090226/gdb/main.c +=================================================================== +--- gdb-6.8.50.20090226.orig/gdb/main.c 2009-02-27 00:04:32.000000000 +0100 ++++ gdb-6.8.50.20090226/gdb/main.c 2009-02-28 07:15:57.000000000 +0100 +@@ -855,7 +855,7 @@ Excess command line arguments ignored. ( + debugging or what directory you are in. */ + + if (home_gdbinit && !inhibit_gdbinit) +- catch_command_errors (source_script, home_gdbinit, 0, RETURN_MASK_ALL); ++ catch_command_errors (source_script, home_gdbinit, -1, RETURN_MASK_ALL); + + /* Now perform all the actions indicated by the arguments. */ + if (cdarg != NULL) +@@ -924,7 +924,7 @@ Can't attach to process and specify a co + /* Read the .gdbinit file in the current directory, *if* it isn't + the same as the $HOME/.gdbinit file (it should exist, also). */ + if (local_gdbinit && !inhibit_gdbinit) +- catch_command_errors (source_script, local_gdbinit, 0, RETURN_MASK_ALL); ++ catch_command_errors (source_script, local_gdbinit, -1, RETURN_MASK_ALL); + + for (i = 0; i < ncmd; i++) + { diff --git a/gdb-6.3-sepcrc-20050402.patch b/gdb-6.3-sepcrc-20050402.patch new file mode 100644 index 0000000..330a739 --- /dev/null +++ b/gdb-6.3-sepcrc-20050402.patch @@ -0,0 +1,82 @@ +2005-04-02 Andrew Cagney + + * symfile.c (separate_debug_file_exists): When the CRCs mismatch + print a warning. + (find_separate_debug_file): Pass in the objfile's name. + +Index: gdb-6.8.50.20081128/gdb/symfile.c +=================================================================== +--- gdb-6.8.50.20081128.orig/gdb/symfile.c 2008-10-03 18:36:10.000000000 +0200 ++++ gdb-6.8.50.20081128/gdb/symfile.c 2008-12-01 16:34:36.000000000 +0100 +@@ -1296,7 +1296,8 @@ get_debug_link_info (struct objfile *obj + } + + static int +-separate_debug_file_exists (const char *name, unsigned long crc) ++separate_debug_file_exists (const char *name, unsigned long crc, ++ const char *parent_name) + { + unsigned long file_crc = 0; + bfd *abfd; +@@ -1316,7 +1317,15 @@ separate_debug_file_exists (const char * + + bfd_close (abfd); + +- return crc == file_crc; ++ if (crc != file_crc) ++ { ++ warning (_("the debug information found in \"%s\"" ++ " does not match \"%s\" (CRC mismatch).\n"), ++ name, parent_name); ++ return 0; ++ } ++ ++ return 1; + } + + char *debug_file_directory = NULL; +@@ -1368,6 +1377,8 @@ find_separate_debug_file (struct objfile + basename = get_debug_link_info (objfile, &crc32); + + if (basename == NULL) ++ /* There's no separate debug info, hence there's no way we could ++ load it => no warning. */ + return NULL; + + dir = xstrdup (objfile->name); +@@ -1395,7 +1406,7 @@ find_separate_debug_file (struct objfile + strcpy (debugfile, dir); + strcat (debugfile, basename); + +- if (separate_debug_file_exists (debugfile, crc32)) ++ if (separate_debug_file_exists (debugfile, crc32, objfile->name)) + { + xfree (basename); + xfree (dir); +@@ -1408,7 +1419,7 @@ find_separate_debug_file (struct objfile + strcat (debugfile, "/"); + strcat (debugfile, basename); + +- if (separate_debug_file_exists (debugfile, crc32)) ++ if (separate_debug_file_exists (debugfile, crc32, objfile->name)) + { + xfree (basename); + xfree (dir); +@@ -1421,7 +1432,7 @@ find_separate_debug_file (struct objfile + strcat (debugfile, dir); + strcat (debugfile, basename); + +- if (separate_debug_file_exists (debugfile, crc32)) ++ if (separate_debug_file_exists (debugfile, crc32, objfile->name)) + { + xfree (basename); + xfree (dir); +@@ -1440,7 +1451,7 @@ find_separate_debug_file (struct objfile + strcat (debugfile, "/"); + strcat (debugfile, basename); + +- if (separate_debug_file_exists (debugfile, crc32)) ++ if (separate_debug_file_exists (debugfile, crc32, objfile->name)) + { + xfree (canon_name); + xfree (basename); diff --git a/gdb-6.3-step-thread-exit-20050211-test.patch b/gdb-6.3-step-thread-exit-20050211-test.patch new file mode 100644 index 0000000..fc73d9f --- /dev/null +++ b/gdb-6.3-step-thread-exit-20050211-test.patch @@ -0,0 +1,195 @@ +2005-02-11 Jeff Johnston + + * testsuite/gdb.threads/step-thread-exit.c: New testcase. + * testsuite/gdb.threads/step-thread-exit.exp: Ditto. + +Index: gdb-6.8.50.20081128/gdb/testsuite/gdb.threads/step-thread-exit.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8.50.20081128/gdb/testsuite/gdb.threads/step-thread-exit.c 2008-12-08 22:21:26.000000000 +0100 +@@ -0,0 +1,50 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2005 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place - Suite 330, ++ Boston, MA 02111-1307, USA. */ ++ ++#include ++#include ++#include ++#include ++ ++void *thread_function (void *ptr) ++{ ++ int *x = (int *)ptr; ++ printf("In thread_function, *x is %d\n", *x); ++} /* thread_function_end */ ++ ++volatile int repeat = 0; ++ ++main() ++{ ++ int ret; ++ pthread_t th; ++ int i = 3; ++ ++ ret = pthread_create (&th, NULL, thread_function, &i); ++ do ++ { ++ repeat = 0; ++ sleep (3); /* sleep */ ++ } ++ while (repeat); ++ pthread_join (th, NULL); ++ return 0; ++} ++ ++ +Index: gdb-6.8.50.20081128/gdb/testsuite/gdb.threads/step-thread-exit.exp +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8.50.20081128/gdb/testsuite/gdb.threads/step-thread-exit.exp 2008-12-08 22:22:14.000000000 +0100 +@@ -0,0 +1,130 @@ ++# This testcase is part of GDB, the GNU debugger. ++ ++# Copyright 2005 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++# Check that GDB can step over a thread exit. ++ ++if $tracelevel { ++ strace $tracelevel ++} ++ ++set prms_id 0 ++set bug_id 0 ++ ++set testfile "step-thread-exit" ++set srcfile ${testfile}.c ++set binfile ${objdir}/${subdir}/${testfile} ++if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable [list debug "incdir=${objdir}"]] != "" } { ++ return -1 ++} ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++# Reset the debug file directory so we can't debug within the C library ++gdb_test "set debug-file-directory ." "" "" ++ ++# ++# Run to `main' where we begin our tests. ++# ++ ++if ![runto_main] then { ++ gdb_suppress_tests ++} ++ ++# FIXME: Currently the main thread will escape/exit before our thread finishes ++# without this setting. ++gdb_test "set scheduler-locking step" ++gdb_test "show scheduler-locking" "Mode for locking scheduler during execution is \"step\"." "check scheduler-locking first" ++ ++set sleep_line [expr [gdb_get_line_number "sleep"]] ++set end_line [expr [gdb_get_line_number "thread_function_end"]] ++ ++gdb_breakpoint "$end_line" ++gdb_test "continue" "Break.*thread_function.*" "continue to thread_function 1" ++ ++# Keep nexting until we cause the thread to exit. We expect the main ++# thread to be stopped and a message printed to tell us we have stepped ++# over the thread exit. ++set test "step over thread exit 1" ++gdb_test_multiple "next" "$test" { ++ -re "\}.*$gdb_prompt $" { ++ send_gdb "next\n" ++ exp_continue ++ } ++ -re "\[Thread .* exited\].*Program received signal SIGSTOP.*$gdb_prompt $" { ++ pass "$test" ++ } ++ -re "start_thread.*$gdb_prompt $" { ++ send_gdb "next\n" ++ exp_continue ++ } ++} ++ ++# Without this fixup we could end up in: ++# #0 0x00110416 in __kernel_vsyscall () ++# #1 0x0011de26 in __lll_unlock_wake_private () from /lib/libpthread.so.0 ++# #2 0x001179f4 in _L_unlock_3164 () from /lib/libpthread.so.0 ++# #3 0x00116f01 in pthread_create@@GLIBC_2.1 () from /lib/libpthread.so.0 ++# #4 0x08048531 in main () at ../.././gdb/testsuite/gdb.threads/step-thread-exit.c:39 ++gdb_breakpoint "$sleep_line" ++gdb_test "set repeat=1" "" "Get to the sleep function prepare 1" ++gdb_test "continue" "Break.*$sleep_line.*" "Get to the sleep function 1" ++ ++gdb_test "bt" "main.*$sleep_line.*" "backtrace after step 1" ++ ++runto_main ++gdb_test "show scheduler-locking" "Mode for locking scheduler during execution is \"step\"." "check scheduler-locking second" ++ ++gdb_breakpoint "$sleep_line" ++gdb_breakpoint "$end_line" ++set test "continue to thread_function 2" ++gdb_test_multiple "continue" "$test" { ++ -re "Break.*thread_function.*$gdb_prompt $" { ++ pass $test ++ } ++ -re "Break.*$sleep_line.*$gdb_prompt $" { ++ gdb_test "set repeat=1" "" "" ++ send_gdb "continue\n" ++ exp_continue ++ } ++} ++ ++# Keep nexting until we cause the thread to exit. In this case, we ++# expect the breakpoint in the main thread to have already triggered ++# and so we should stop there with a message that we stepped over ++# the thread exit. ++set test "step over thread exit 2" ++gdb_test_multiple "next" "$test" { ++ -re "\}.*$gdb_prompt $" { ++ send_gdb "next\n" ++ exp_continue ++ } ++ -re "\[Thread .* exited\].*Break.*$sleep_line.*$gdb_prompt $" { ++ pass "$test (breakpoint hit)" ++ } ++ -re "\[Thread .* exited\].*$gdb_prompt $" { ++ pass "$test (breakpoint not hit)" ++ } ++ -re "start_thread.*$gdb_prompt $" { ++ send_gdb "next\n" ++ exp_continue ++ } ++} ++ diff --git a/gdb-6.3-terminal-fix-20050214.patch b/gdb-6.3-terminal-fix-20050214.patch new file mode 100644 index 0000000..d97d6a2 --- /dev/null +++ b/gdb-6.3-terminal-fix-20050214.patch @@ -0,0 +1,28 @@ +2005-02-14 Jeff Johnston + + * top.c (gdb_readline_wrapper): Ensure terminal is gdb's before calling + readline. + +2007-10-14 Jan Kratochvil + + Port to GDB-6.7. + +Index: gdb-6.7/gdb/top.c +=================================================================== +--- gdb-6.7.orig/gdb/top.c 2007-09-02 23:13:56.000000000 +0200 ++++ gdb-6.7/gdb/top.c 2007-10-14 23:38:27.000000000 +0200 +@@ -795,6 +795,14 @@ gdb_readline_wrapper (char *prompt) + + back_to = make_cleanup (gdb_readline_wrapper_cleanup, cleanup); + ++ /* Before calling readline, ensure we have the terminal. If we don't ++ have the terminal and call readline, we risk the possibility of ++ gdb being thrown into the background. This problem occurs when ++ we attach to a background process on the same terminal the background ++ process was started from and then perform some action which requires ++ a page break prompt. */ ++ terminal_ours (); ++ + /* Display our prompt and prevent double prompt display. */ + display_gdb_prompt (prompt); + rl_already_prompted = 1; diff --git a/gdb-6.3-test-dtorfix-20050121.patch b/gdb-6.3-test-dtorfix-20050121.patch new file mode 100644 index 0000000..df46859 --- /dev/null +++ b/gdb-6.3-test-dtorfix-20050121.patch @@ -0,0 +1,263 @@ +Index: gdb/testsuite/ChangeLog +2005-01-21 Jeff Johnston + + * gdb.cp/constructortest.exp: New test. + * gdb.cp/constructortest.cc: Ditto. + * gdb.cp/templates.exp: Change break of dtor to be fully quoted. + +2007-09-22 Jan Kratochvil + + * gdb.cp/constructortest.exp, gdb.cp/constructortest.cc: Test also the + `$delete' destructor variant. + +2007-09-25 Jan Kratochvil + + * gdb.cp/constructortest.exp: Delete the FIXME workaround of restarting + the whole GDB. + +2007-10-05 Jan Kratochvil + + * gdb.cp/constructortest.exp: Test BREAKPOINT_RE_SET for multiple PCs + by PIE. + * gdb.cp/constructortest.exp: Handle the change of settings breakpoints + always at all the ctor/dtor variants. + +[ Removed the `gdb.cp/templates.exp' patch. ] +[ Updated the patch for "(X location") of GDB-6.8+. ] + +--- gdb-6.3/gdb/testsuite/gdb.cp/constructortest.cc.fix Fri Jan 21 17:06:56 2005 ++++ gdb-6.3/gdb/testsuite/gdb.cp/constructortest.cc Fri Jan 21 17:05:18 2005 +@@ -0,0 +1,99 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2005 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place - Suite 330, ++ Boston, MA 02111-1307, USA. */ ++ ++class A ++{ ++ public: ++ A(); ++ ~A(); ++ int k; ++ private: ++ int x; ++}; ++ ++class B: public A ++{ ++ public: ++ B(); ++ private: ++ int y; ++}; ++ ++/* C and D are for the $delete destructor. */ ++ ++class C ++{ ++ public: ++ C(); ++ virtual ~C(); ++ private: ++ int x; ++}; ++ ++class D: public C ++{ ++ public: ++ D(); ++ private: ++ int y; ++}; ++ ++int main(int argc, char *argv[]) ++{ ++ A* a = new A; ++ B* b = new B; ++ D* d = new D; ++ delete a; ++ delete b; ++ delete d; ++ return 0; ++} ++ ++A::A() /* Constructor A */ ++{ ++ x = 1; /* First line A */ ++ k = 4; /* Second line A */ ++} ++ ++A::~A() /* Destructor A */ ++{ ++ x = 3; /* First line ~A */ ++ k = 6; /* Second line ~A */ ++} ++ ++B::B() ++{ ++ y = 2; /* First line B */ ++ k = 5; ++} ++ ++C::C() /* Constructor C */ ++{ ++ x = 1; /* First line C */ ++} ++ ++C::~C() /* Destructor C */ ++{ ++ x = 3; /* First line ~C */ ++} ++ ++D::D() ++{ ++ y = 2; /* First line D */ ++} +--- gdb-6.3/gdb/testsuite/gdb.cp/constructortest.exp.fix Fri Jan 21 17:07:02 2005 ++++ gdb-6.3/gdb/testsuite/gdb.cp/constructortest.exp Fri Jan 21 17:05:29 2005 +@@ -0,0 +1,131 @@ ++# This testcase is part of GDB, the GNU debugger. ++ ++# Copyright 2005, 2007 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++# Check that GDB can break at multiple forms of constructors. ++ ++if $tracelevel { ++ strace $tracelevel ++} ++ ++set prms_id 0 ++set bug_id 0 ++ ++set testfile "constructortest" ++set srcfile ${testfile}.cc ++set binfile ${objdir}/${subdir}/${testfile} ++# PIE is required for testing proper BREAKPOINT_RE_SET of the multiple-PC ++# breakpoints. ++if {[gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug c++ "additional_flags=-fpie -pie"}] != "" } { ++ return -1 ++} ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++# ++# Run to `main' where we begin our tests. ++# ++ ++if ![runto_main] then { ++ gdb_suppress_tests ++} ++ ++# Break on the various forms of the A::A constructor ++gdb_test "break A\:\:A" "Breakpoint 2 at .* \\(2 locations\\)" "breaking on A::A" ++ ++# Verify that we break for the A constructor two times ++# Once for new A and once for new B ++gdb_continue_to_breakpoint "First line A" ++gdb_test "bt" "#0.*A.*#1.*main.*" "Verify in in-charge A::A" ++gdb_continue_to_breakpoint "First line A" ++gdb_test "bt" "#0.*A.*#1.*B.*#2.*main.*" "Verify in not-in-charge A::A" ++ ++# Now do the same for destructors ++gdb_test "break 'A::~A()'" "" ++ ++# Verify that we break for the A destructor two times ++# Once for delete a and once for delete b ++gdb_continue_to_breakpoint "First line ~A" ++gdb_test "bt" "#0.*~A.*#1.*main.*" "Verify in in-charge A::~A" ++gdb_continue_to_breakpoint "First line ~A" ++gdb_test "bt" "#0.*~A.*#1.*~B.*#2.*main.*" "Verify in not-in-charge A::~A" ++ ++ ++# Verify that we can break by line number in a constructor and find ++# both occurrences ++runto_main ++gdb_test "break 'A::A()'" "" "break in constructor A 2" ++gdb_continue_to_breakpoint "First line A" ++set second_line [gdb_get_line_number "Second line A"] ++gdb_test "break $second_line" "Breakpoint .*, line $second_line. \\(2 locations\\)" "break by line in constructor" ++gdb_continue_to_breakpoint "Second line A" ++gdb_test "bt" "#0.*A.*#1.*main.*" "Verify in in-charge A::A second line" ++gdb_continue_to_breakpoint "Second line A" ++gdb_test "bt" "#0.*A.*#1.*B.*#2.*main.*" "Verify in not-in-charge A::A second line" ++ ++# Verify that we can break by line number in a destructor and find ++# both occurrences ++gdb_test "break 'A::~A()'" "" "break in constructor ~A 2" ++gdb_continue_to_breakpoint "First line ~A" ++set second_line_dtor [gdb_get_line_number "Second line ~A"] ++gdb_test "break $second_line_dtor" "Breakpoint .*, line $second_line_dtor. \\(2 locations\\)" "break by line in destructor" ++gdb_continue_to_breakpoint "Second line ~A" ++gdb_test "bt" "#0.*A.*#1.*main.*" "Verify in in-charge A::~A second line" ++# FIXME: Analyse this case better. ++gdb_continue_to_breakpoint "Second line ~A" ++gdb_test "bt" "#0.*A.*#1.*main.*" "Verify in A::~A second line #2" ++gdb_continue_to_breakpoint "Second line ~A" ++gdb_test "bt" "#0.*A.*#1.*B.*#2.*main.*" "Verify in not-in-charge A::~A second line" ++ ++ ++# Test now the $delete destructors. ++ ++gdb_load ${binfile} ++runto_main ++ ++# Break on the various forms of the C::~C destructor ++gdb_test "break C\:\:~C" "Breakpoint .* \\(3 locations\\)" "breaking on C::~C" ++gdb_continue_to_breakpoint "First line ~C" ++ ++# Verify that we can break by line number in a destructor and find ++# the $delete occurence ++ ++gdb_load ${binfile} ++delete_breakpoints ++ ++set first_line_dtor [gdb_get_line_number "First line ~C"] ++gdb_test "break $first_line_dtor" "Breakpoint .*, line $first_line_dtor. \\(3 locations\\)" "break by line in destructor" ++ ++# Run to `main' where we begin our tests. ++# Set the breakpoints first to test PIE multiple-PC BREAKPOINT_RE_SET. ++# RUNTO_MAIN or RUNTO MAIN are not usable here as it runs DELETE_BREAKPOINTS. ++ ++if ![gdb_breakpoint main] { ++ gdb_suppress_tests ++} ++gdb_run_cmd ++set test "running to main" ++gdb_test_multiple "" $test { ++ -re "Breakpoint \[0-9\]*, main .*$gdb_prompt $" { ++ pass $test ++ } ++} ++ ++gdb_continue_to_breakpoint "First line ~C" diff --git a/gdb-6.3-test-movedir-20050125.patch b/gdb-6.3-test-movedir-20050125.patch new file mode 100644 index 0000000..eb3cf73 --- /dev/null +++ b/gdb-6.3-test-movedir-20050125.patch @@ -0,0 +1,105 @@ +2005-01-25 Elena Zannoni + + * gdb.base/move-dir.exp: New test. + * gdb.base/move-dir.c: Ditto. + * gdb.base/move-dir.h: Ditto. + +Index: gdb-6.8.50.20081128/gdb/testsuite/gdb.base/move-dir.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8.50.20081128/gdb/testsuite/gdb.base/move-dir.c 2008-12-07 23:57:41.000000000 +0100 +@@ -0,0 +1,10 @@ ++#include ++#include ++#include "move-dir.h" ++ ++int main() { ++ const char* hw = "hello world."; ++ printf ("%s\n", hw);; ++ other(); ++} ++ +Index: gdb-6.8.50.20081128/gdb/testsuite/gdb.base/move-dir.exp +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8.50.20081128/gdb/testsuite/gdb.base/move-dir.exp 2008-12-07 10:13:01.000000000 +0100 +@@ -0,0 +1,67 @@ ++# Copyright 2005 ++# Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++# Please email any bugs, comments, and/or additions to this file to: ++# bug-gdb@prep.ai.mit.edu ++ ++if $tracelevel then { ++ strace $tracelevel ++} ++ ++set prms_id 0 ++set bug_id 0 ++ ++set testfile "move-dir" ++set srcfile ${testfile}.c ++set incfile ${testfile}.h ++set binfile ${objdir}/${subdir}/${testfile} ++ ++set testdir "${objdir}/${subdir}/incdir" ++ ++remote_exec build "mkdir $testdir" ++remote_exec build "cp ${srcdir}/${subdir}/${srcfile} ${objdir}/${subdir}" ++remote_exec build "cp ${srcdir}/${subdir}/${incfile} ${testdir}" ++ ++set additional_flags "additional_flags=-I${subdir}/incdir" ++ ++if { [gdb_compile "${objdir}/${subdir}/${srcfile}" "${binfile}" executable [list debug $additional_flags]] != "" } { ++ gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail." ++} ++ ++# Create and source the file that provides information about the compiler ++# used to compile the test case. ++ ++if [get_compiler_info ${binfile}] { ++ return -1; ++} ++ ++ ++set oldtimeout $timeout ++set timeout [expr "$timeout + 60"] ++ ++# Start with a fresh gdb. ++ ++gdb_exit ++gdb_start ++gdb_test "cd ../.." "" "" ++gdb_load ${binfile} ++gdb_test "list main" ".*hw.*other.*" "found main" ++gdb_test "list other" ".*ostring.*" "found include file" ++ ++ ++set timeout $oldtimeout ++return 0 +Index: gdb-6.8.50.20081128/gdb/testsuite/gdb.base/move-dir.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8.50.20081128/gdb/testsuite/gdb.base/move-dir.h 2008-12-07 10:13:01.000000000 +0100 +@@ -0,0 +1,7 @@ ++#include ++ ++void other() { ++ const char* ostring = "other"; ++ printf ("%s\n", ostring);; ++} ++ diff --git a/gdb-6.3-test-pie-20050107.patch b/gdb-6.3-test-pie-20050107.patch new file mode 100644 index 0000000..48bb8d9 --- /dev/null +++ b/gdb-6.3-test-pie-20050107.patch @@ -0,0 +1,2121 @@ +Index: gdb-6.8.50.20081128/gdb/testsuite/configure.ac +=================================================================== +--- gdb-6.8.50.20081128.orig/gdb/testsuite/configure.ac 2008-12-09 17:02:39.000000000 +0100 ++++ gdb-6.8.50.20081128/gdb/testsuite/configure.ac 2008-12-09 17:02:55.000000000 +0100 +@@ -116,6 +116,6 @@ AC_OUTPUT([Makefile \ + gdb.cp/Makefile gdb.disasm/Makefile gdb.dwarf2/Makefile \ + gdb.fortran/Makefile gdb.server/Makefile \ + gdb.java/Makefile gdb.mi/Makefile gdb.modula2/Makefile \ +- gdb.objc/Makefile gdb.opt/Makefile gdb.pascal/Makefile \ ++ gdb.objc/Makefile gdb.opt/Makefile gdb.pascal/Makefile gdb.pie/Makefile \ + gdb.python/Makefile \ + gdb.threads/Makefile gdb.trace/Makefile gdb.xml/Makefile]) +Index: gdb-6.8.50.20081128/gdb/testsuite/configure +=================================================================== +--- gdb-6.8.50.20081128.orig/gdb/testsuite/configure 2008-12-09 17:02:39.000000000 +0100 ++++ gdb-6.8.50.20081128/gdb/testsuite/configure 2008-12-09 17:02:55.000000000 +0100 +@@ -3131,7 +3131,7 @@ done + + + +- ac_config_files="$ac_config_files Makefile gdb.ada/Makefile gdb.arch/Makefile gdb.asm/Makefile gdb.base/Makefile gdb.cp/Makefile gdb.disasm/Makefile gdb.dwarf2/Makefile gdb.fortran/Makefile gdb.server/Makefile gdb.java/Makefile gdb.mi/Makefile gdb.modula2/Makefile gdb.objc/Makefile gdb.opt/Makefile gdb.pascal/Makefile gdb.python/Makefile gdb.threads/Makefile gdb.trace/Makefile gdb.xml/Makefile" ++ ac_config_files="$ac_config_files Makefile gdb.ada/Makefile gdb.arch/Makefile gdb.asm/Makefile gdb.base/Makefile gdb.cp/Makefile gdb.disasm/Makefile gdb.dwarf2/Makefile gdb.fortran/Makefile gdb.server/Makefile gdb.java/Makefile gdb.mi/Makefile gdb.modula2/Makefile gdb.objc/Makefile gdb.opt/Makefile gdb.pascal/Makefile gdb.pie/Makefile gdb.python/Makefile gdb.threads/Makefile gdb.trace/Makefile gdb.xml/Makefile" + cat >confcache <<\_ACEOF + # This file is a shell script that caches the results of configure + # tests run on this system so they can be shared between configure +@@ -3698,6 +3698,7 @@ do + "gdb.objc/Makefile" ) CONFIG_FILES="$CONFIG_FILES gdb.objc/Makefile" ;; + "gdb.opt/Makefile" ) CONFIG_FILES="$CONFIG_FILES gdb.opt/Makefile" ;; + "gdb.pascal/Makefile" ) CONFIG_FILES="$CONFIG_FILES gdb.pascal/Makefile" ;; ++ "gdb.pie/Makefile" ) CONFIG_FILES="$CONFIG_FILES gdb.pie/Makefile" ;; + "gdb.python/Makefile" ) CONFIG_FILES="$CONFIG_FILES gdb.python/Makefile" ;; + "gdb.threads/Makefile" ) CONFIG_FILES="$CONFIG_FILES gdb.threads/Makefile" ;; + "gdb.trace/Makefile" ) CONFIG_FILES="$CONFIG_FILES gdb.trace/Makefile" ;; +Index: gdb-6.8.50.20081128/gdb/testsuite/gdb.pie/attach.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8.50.20081128/gdb/testsuite/gdb.pie/attach.c 2008-12-09 17:02:55.000000000 +0100 +@@ -0,0 +1,20 @@ ++/* This program is intended to be started outside of gdb, and then ++ attached to by gdb. Thus, it simply spins in a loop. The loop ++ is exited when & if the variable 'should_exit' is non-zero. (It ++ is initialized to zero in this program, so the loop will never ++ exit unless/until gdb sets the variable to non-zero.) ++ */ ++#include ++ ++int should_exit = 0; ++ ++int main () ++{ ++ int local_i = 0; ++ ++ while (! should_exit) ++ { ++ local_i++; ++ } ++ return 0; ++} +Index: gdb-6.8.50.20081128/gdb/testsuite/gdb.pie/attach2.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8.50.20081128/gdb/testsuite/gdb.pie/attach2.c 2008-12-09 17:02:55.000000000 +0100 +@@ -0,0 +1,24 @@ ++/* This program is intended to be started outside of gdb, and then ++ attached to by gdb. Thus, it simply spins in a loop. The loop ++ is exited when & if the variable 'should_exit' is non-zero. (It ++ is initialized to zero in this program, so the loop will never ++ exit unless/until gdb sets the variable to non-zero.) ++ */ ++#include ++#include ++#include ++ ++int should_exit = 0; ++ ++int main () ++{ ++ int local_i = 0; ++ ++ sleep( 10 ); /* System call causes register fetch to fail */ ++ /* This is a known HPUX "feature" */ ++ while (! should_exit) ++ { ++ local_i++; ++ } ++ return (0); ++} +Index: gdb-6.8.50.20081128/gdb/testsuite/gdb.pie/break.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8.50.20081128/gdb/testsuite/gdb.pie/break.c 2008-12-09 17:02:55.000000000 +0100 +@@ -0,0 +1,146 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 1992, 1993, 1994, 1995, 1999, 2002, 2003 Free Software ++ Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++ Please email any bugs, comments, and/or additions to this file to: ++ bug-gdb@prep.ai.mit.edu */ ++ ++#ifdef vxworks ++ ++# include ++ ++/* VxWorks does not supply atoi. */ ++static int ++atoi (z) ++ char *z; ++{ ++ int i = 0; ++ ++ while (*z >= '0' && *z <= '9') ++ i = i * 10 + (*z++ - '0'); ++ return i; ++} ++ ++/* I don't know of any way to pass an array to VxWorks. This function ++ can be called directly from gdb. */ ++ ++vxmain (arg) ++char *arg; ++{ ++ char *argv[2]; ++ ++ argv[0] = ""; ++ argv[1] = arg; ++ main (2, argv, (char **) 0); ++} ++ ++#else /* ! vxworks */ ++# include ++# include ++#endif /* ! vxworks */ ++ ++#ifdef PROTOTYPES ++extern int marker1 (void); ++extern int marker2 (int a); ++extern void marker3 (char *a, char *b); ++extern void marker4 (long d); ++#else ++extern int marker1 (); ++extern int marker2 (); ++extern void marker3 (); ++extern void marker4 (); ++#endif ++ ++/* ++ * This simple classical example of recursion is useful for ++ * testing stack backtraces and such. ++ */ ++ ++#ifdef PROTOTYPES ++int factorial(int); ++ ++int ++main (int argc, char **argv, char **envp) ++#else ++int ++main (argc, argv, envp) ++int argc; ++char *argv[], **envp; ++#endif ++{ ++#ifdef usestubs ++ set_debug_traps(); /* set breakpoint 5 here */ ++ breakpoint(); ++#endif ++ if (argc == 12345) { /* an unlikely value < 2^16, in case uninited */ /* set breakpoint 6 here */ ++ fprintf (stderr, "usage: factorial \n"); ++ return 1; ++ } ++ printf ("%d\n", factorial (atoi ("6"))); /* set breakpoint 1 here */ ++ /* set breakpoint 12 here */ ++ marker1 (); /* set breakpoint 11 here */ ++ marker2 (43); /* set breakpoint 20 here */ ++ marker3 ("stack", "trace"); /* set breakpoint 21 here */ ++ marker4 (177601976L); ++ argc = (argc == 12345); /* This is silly, but we can step off of it */ /* set breakpoint 2 here */ ++ return argc; /* set breakpoint 10 here */ ++} ++ ++#ifdef PROTOTYPES ++int factorial (int value) ++#else ++int factorial (value) ++int value; ++#endif ++{ ++ if (value > 1) { /* set breakpoint 7 here */ ++ value *= factorial (value - 1); ++ } ++ return (value); /* set breakpoint 19 here */ ++} ++ ++#ifdef PROTOTYPES ++int multi_line_if_conditional (int a, int b, int c) ++#else ++int multi_line_if_conditional (a, b, c) ++ int a, b, c; ++#endif ++{ ++ if (a /* set breakpoint 3 here */ ++ && b ++ && c) ++ return 0; ++ else ++ return 1; ++} ++ ++#ifdef PROTOTYPES ++int multi_line_while_conditional (int a, int b, int c) ++#else ++int multi_line_while_conditional (a, b, c) ++ int a, b, c; ++#endif ++{ ++ while (a /* set breakpoint 4 here */ ++ && b ++ && c) ++ { ++ a--, b--, c--; ++ } ++ return 0; ++} +Index: gdb-6.8.50.20081128/gdb/testsuite/gdb.pie/break1.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8.50.20081128/gdb/testsuite/gdb.pie/break1.c 2008-12-09 17:02:55.000000000 +0100 +@@ -0,0 +1,44 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 1992, 1993, 1994, 1995, 1999, 2002, 2003 Free Software ++ Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++ Please email any bugs, comments, and/or additions to this file to: ++ bug-gdb@prep.ai.mit.edu */ ++ ++/* The code for this file was extracted from the gdb testsuite ++ testcase "break.c". */ ++ ++/* The following functions do nothing useful. They are included ++ simply as places to try setting breakpoints at. They are ++ explicitly "one-line functions" to verify that this case works ++ (some versions of gcc have or have had problems with this). ++ ++ These functions are in a separate source file to prevent an ++ optimizing compiler from inlining them and optimizing them away. */ ++ ++#ifdef PROTOTYPES ++int marker1 (void) { return (0); } /* set breakpoint 15 here */ ++int marker2 (int a) { return (1); } /* set breakpoint 8 here */ ++void marker3 (char *a, char *b) {} /* set breakpoint 17 here */ ++void marker4 (long d) {} /* set breakpoint 14 here */ ++#else ++int marker1 () { return (0); } /* set breakpoint 16 here */ ++int marker2 (a) int a; { return (1); } /* set breakpoint 9 here */ ++void marker3 (a, b) char *a, *b; {} /* set breakpoint 18 here */ ++void marker4 (d) long d; {} /* set breakpoint 13 here */ ++#endif +Index: gdb-6.8.50.20081128/gdb/testsuite/gdb.pie/coremaker.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8.50.20081128/gdb/testsuite/gdb.pie/coremaker.c 2008-12-09 17:02:55.000000000 +0100 +@@ -0,0 +1,142 @@ ++/* Copyright 1992, 1993, 1994, 1995, 1996, 1999 ++ Free Software Foundation, Inc. ++ ++ This file is part of GDB. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or (at ++ your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, but ++ WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place - Suite 330, ++ Boston, MA 02111-1307, USA. */ ++ ++/* Simple little program that just generates a core dump from inside some ++ nested function calls. */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifndef __STDC__ ++#define const /**/ ++#endif ++ ++#define MAPSIZE (8 * 1024) ++ ++/* Don't make these automatic vars or we will have to walk back up the ++ stack to access them. */ ++ ++char *buf1; ++char *buf2; ++ ++int coremaker_data = 1; /* In Data section */ ++int coremaker_bss; /* In BSS section */ ++ ++const int coremaker_ro = 201; /* In Read-Only Data section */ ++ ++/* Note that if the mapping fails for any reason, we set buf2 ++ to -1 and the testsuite notices this and reports it as ++ a failure due to a mapping error. This way we don't have ++ to test for specific errors when running the core maker. */ ++ ++void ++mmapdata () ++{ ++ int j, fd; ++ ++ /* Allocate and initialize a buffer that will be used to write ++ the file that is later mapped in. */ ++ ++ buf1 = (char *) malloc (MAPSIZE); ++ for (j = 0; j < MAPSIZE; ++j) ++ { ++ buf1[j] = j; ++ } ++ ++ /* Write the file to map in */ ++ ++ fd = open ("coremmap.data", O_CREAT | O_RDWR, 0666); ++ if (fd == -1) ++ { ++ perror ("coremmap.data open failed"); ++ buf2 = (char *) -1; ++ return; ++ } ++ write (fd, buf1, MAPSIZE); ++ ++ /* Now map the file into our address space as buf2 */ ++ ++ buf2 = (char *) mmap (0, MAPSIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); ++ if (buf2 == (char *) -1) ++ { ++ perror ("mmap failed"); ++ return; ++ } ++ ++ /* Verify that the original data and the mapped data are identical. ++ If not, we'd rather fail now than when trying to access the mapped ++ data from the core file. */ ++ ++ for (j = 0; j < MAPSIZE; ++j) ++ { ++ if (buf1[j] != buf2[j]) ++ { ++ fprintf (stderr, "mapped data is incorrect"); ++ buf2 = (char *) -1; ++ return; ++ } ++ } ++} ++ ++void ++func2 () ++{ ++ int coremaker_local[5]; ++ int i; ++ ++#ifdef SA_FULLDUMP ++ /* Force a corefile that includes the data section for AIX. */ ++ { ++ struct sigaction sa; ++ ++ sigaction (SIGABRT, (struct sigaction *)0, &sa); ++ sa.sa_flags |= SA_FULLDUMP; ++ sigaction (SIGABRT, &sa, (struct sigaction *)0); ++ } ++#endif ++ ++ /* Make sure that coremaker_local doesn't get optimized away. */ ++ for (i = 0; i < 5; i++) ++ coremaker_local[i] = i; ++ coremaker_bss = 0; ++ for (i = 0; i < 5; i++) ++ coremaker_bss += coremaker_local[i]; ++ coremaker_data = coremaker_ro + 1; ++ abort (); ++} ++ ++void ++func1 () ++{ ++ func2 (); ++} ++ ++int main () ++{ ++ mmapdata (); ++ func1 (); ++ return 0; ++} ++ +Index: gdb-6.8.50.20081128/gdb/testsuite/gdb.pie/attach.exp +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8.50.20081128/gdb/testsuite/gdb.pie/attach.exp 2008-12-09 17:02:55.000000000 +0100 +@@ -0,0 +1,432 @@ ++# Copyright 1997, 1999, 2002 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ ++ ++# Please email any bugs, comments, and/or additions to this file to: ++# bug-gdb@prep.ai.mit.edu ++ ++if $tracelevel then { ++ strace $tracelevel ++ } ++ ++set prms_id 0 ++set bug_id 0 ++ ++# On HP-UX 11.0, this test is causing a process running the program ++# "attach" to be left around spinning. Until we figure out why, I am ++# commenting out the test to avoid polluting tiamat (our 11.0 nightly ++# test machine) with these processes. RT ++# ++# Setting the magic bit in the target app should work. I added a ++# "kill", and also a test for the R3 register warning. JB ++if { [istarget "hppa*-*-hpux*"] } { ++ return 0 ++} ++ ++# are we on a target board ++if [is_remote target] then { ++ return 0 ++} ++ ++set testfile "attach" ++set srcfile ${testfile}.c ++set srcfile2 ${testfile}2.c ++set binfile ${objdir}/${subdir}/${testfile} ++set binfile2 ${objdir}/${subdir}/${testfile}2 ++set escapedbinfile [string_to_regexp ${objdir}/${subdir}/${testfile}] ++set cleanupfile ${objdir}/${subdir}/${testfile}.awk ++ ++#execute_anywhere "rm -f ${binfile} ${binfile2}" ++remote_exec build "rm -f ${binfile} ${binfile2}" ++# For debugging this test ++# ++#log_user 1 ++ ++# Clean out any old files from past runs. ++# ++remote_exec build "${cleanupfile}" ++ ++# build the first test case ++# ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug "additional_flags= -fpie -pie"}] != "" } { ++ gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail." ++} ++ ++# Build the in-system-call test ++ ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile2}" "${binfile2}" executable {debug "additional_flags= -fpie -pie"}] != "" } { ++ gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail." ++} ++ ++if [get_compiler_info ${binfile}] { ++ return -1 ++} ++ ++proc do_attach_tests {} { ++ global gdb_prompt ++ global binfile ++ global escapedbinfile ++ global srcfile ++ global testfile ++ global objdir ++ global subdir ++ global timeout ++ ++ # Start the program running and then wait for a bit, to be sure ++ # that it can be attached to. ++ # ++ set testpid [eval exec $binfile &] ++ exec sleep 2 ++ ++ # Verify that we cannot attach to nonsense. ++ # ++ send_gdb "attach abc\n" ++ gdb_expect { ++ -re ".*Illegal process-id: abc.*$gdb_prompt $"\ ++ {pass "attach to nonsense is prohibited"} ++ -re "Attaching to.*, process .*couldn't open /proc file.*$gdb_prompt $"\ ++ { ++ # Response expected from /proc-based systems. ++ pass "attach to nonsense is prohibited" ++ } ++ -re "Attaching to.*$gdb_prompt $"\ ++ {fail "attach to nonsense is prohibited (bogus pid allowed)"} ++ -re "$gdb_prompt $" {fail "attach to nonsense is prohibited"} ++ timeout {fail "(timeout) attach to nonsense is prohibited"} ++ } ++ ++ # Verify that we cannot attach to what appears to be a valid ++ # process ID, but is a process that doesn't exist. Traditionally, ++ # most systems didn't have a process with ID 0, so we take that as ++ # the default. However, there are a few exceptions. ++ # ++ set boguspid 0 ++ if { [istarget "*-*-*bsd*"] } { ++ # In FreeBSD 5.0, PID 0 is used for "swapper". Use -1 instead ++ # (which should have the desired effect on any version of ++ # FreeBSD, and probably other *BSD's too). ++ set boguspid -1 ++ } ++ send_gdb "attach $boguspid\n" ++ gdb_expect { ++ -re "Attaching to.*, process $boguspid.*No such process.*$gdb_prompt $"\ ++ { ++ # Response expected on ptrace-based systems (i.e. HP-UX 10.20). ++ pass "attach to nonexistent process is prohibited" ++ } ++ -re "Attaching to.*, process $boguspid failed.*Hint.*$gdb_prompt $"\ ++ { ++ # Response expected on ttrace-based systems (i.e. HP-UX 11.0). ++ pass "attach to nonexistent process is prohibited" ++ } ++ -re "Attaching to.*, process $boguspid.*denied.*$gdb_prompt $"\ ++ {pass "attach to nonexistent process is prohibited"} ++ -re "Attaching to.*, process $boguspid.*not permitted.*$gdb_prompt $"\ ++ {pass "attach to nonexistent process is prohibited"} ++ -re "Attaching to.*, process .*couldn't open /proc file.*$gdb_prompt $"\ ++ { ++ # Response expected from /proc-based systems. ++ pass "attach to nonexistent process is prohibited" ++ } ++ -re "$gdb_prompt $" {fail "attach to nonexistent process is prohibited"} ++ timeout { ++ fail "(timeout) attach to nonexistent process is prohibited" ++ } ++ } ++ ++ # Verify that we can attach to the process by first giving its ++ # executable name via the file command, and using attach with ++ # the process ID. ++ # ++ # (Actually, the test system appears to do this automatically ++ # for us. So, we must also be prepared to be asked if we want ++ # to discard an existing set of symbols.) ++ # ++ send_gdb "file $binfile\n" ++ gdb_expect { ++ -re "Load new symbol table from.*y or n.*$" { ++ send_gdb "y\n" ++ gdb_expect { ++ -re "Reading symbols from $escapedbinfile\.\.\.*done.*$gdb_prompt $"\ ++ {pass "(re)set file, before attach1"} ++ -re "$gdb_prompt $" {fail "(re)set file, before attach1"} ++ timeout {fail "(timeout) (re)set file, before attach1"} ++ } ++ } ++ -re "Reading symbols from $escapedbinfile\.\.\.*done.*$gdb_prompt $"\ ++ {pass "set file, before attach1"} ++ -re "$gdb_prompt $" {fail "set file, before attach1"} ++ timeout {fail "(timeout) set file, before attach1"} ++ } ++ ++ send_gdb "attach $testpid\n" ++ gdb_expect { ++ -re "Attaching to program.*`?$escapedbinfile'?, process $testpid.*main.*at .*$srcfile:.*$gdb_prompt $"\ ++ {pass "attach1, after setting file"} ++ -re "$gdb_prompt $" {fail "attach1, after setting file"} ++ timeout {fail "(timeout) attach1, after setting file"} ++ } ++ ++ # Verify that we can "see" the variable "should_exit" in the ++ # program, and that it is zero. ++ # ++ send_gdb "print should_exit\n" ++ gdb_expect { ++ -re ".* = 0.*$gdb_prompt $"\ ++ {pass "after attach1, print should_exit"} ++ -re "$gdb_prompt $" {fail "after attach1, print should_exit"} ++ timeout {fail "(timeout) after attach1, print should_exit"} ++ } ++ ++ # Detach the process. ++ # ++ send_gdb "detach\n" ++ gdb_expect { ++ -re "Detaching from program: .*$escapedbinfile.*$gdb_prompt $"\ ++ {pass "attach1 detach"} ++ -re "$gdb_prompt $" {fail "attach1 detach"} ++ timeout {fail "(timeout) attach1 detach"} ++ } ++ ++ # Wait a bit for gdb to finish detaching ++ # ++ exec sleep 5 ++ ++ # Purge the symbols from gdb's brain. (We want to be certain ++ # the next attach, which won't be preceded by a "file" command, ++ # is really getting the executable file without our help.) ++ # ++ set old_timeout $timeout ++ set timeout 15 ++ send_gdb "file\n" ++ gdb_expect { ++ -re ".*gdb internal error.*$" { ++ fail "Internal error, prob. Memory corruption" ++ } ++ -re "No executable file now.*Discard symbol table.*y or n.*$" { ++ send_gdb "y\n" ++ gdb_expect { ++ -re "No symbol file now.*$gdb_prompt $"\ ++ {pass "attach1, purging symbols after detach"} ++ -re "$gdb_prompt $" {fail "attach1, purging symbols after detach"} ++ timeout {fail "(timeout) attach1, purging symbols after detach"} ++ } ++ } ++ -re "$gdb_prompt $" {fail "attach1, purging file after detach"} ++ timeout { ++ fail "(timeout) attach1, purging file after detach" ++ } ++ } ++ set timeout $old_timeout ++ ++ # Verify that we can attach to the process just by giving the ++ # process ID. ++ # ++ send_gdb "attach $testpid\n" ++ gdb_expect { ++ -re "Attaching to process $testpid.*Reading symbols from $escapedbinfile.*main.*at .*$gdb_prompt $"\ ++ {pass "attach2"} ++ -re "$gdb_prompt $" {fail "attach2"} ++ timeout {fail "(timeout) attach2"} ++ } ++ ++ # Verify that we can modify the variable "should_exit" in the ++ # program. ++ # ++ send_gdb "set should_exit=1\n" ++ gdb_expect { ++ -re "$gdb_prompt $" {pass "after attach2, set should_exit"} ++ timeout {fail "(timeout) after attach2, set should_exit"} ++ } ++ ++ # Verify that the modification really happened. ++ # ++ send_gdb "tbreak 19\n" ++ gdb_expect { ++ -re "reakpoint .*at.*$srcfile, line 19.*$gdb_prompt $"\ ++ {pass "after attach2, set tbreak postloop"} ++ -re "$gdb_prompt $" {fail "after attach2, set tbreak postloop"} ++ timeout {fail "(timeout) after attach2, set tbreak postloop"} ++ } ++ send_gdb "continue\n" ++ gdb_expect { ++ -re "main.*at.*$srcfile:19.*$gdb_prompt $"\ ++ {pass "after attach2, reach tbreak postloop"} ++ -re "$gdb_prompt $" {fail "after attach2, reach tbreak postloop"} ++ timeout {fail "(timeout) after attach2, reach tbreak postloop"} ++ } ++ ++ # Allow the test process to exit, to cleanup after ourselves. ++ # ++ send_gdb "continue\n" ++ gdb_expect { ++ -re "Program exited normally.*$gdb_prompt $"\ ++ {pass "after attach2, exit"} ++ -re "$gdb_prompt $" {fail "after attach2, exit"} ++ timeout {fail "(timeout) after attach2, exit"} ++ } ++ ++ # Make sure we don't leave a process around to confuse ++ # the next test run (and prevent the compile by keeping ++ # the text file busy), in case the "set should_exit" didn't ++ # work. ++ # ++ remote_exec build "kill -9 ${testpid}" ++ # Start the program running and then wait for a bit, to be sure ++ # that it can be attached to. ++ # ++ set testpid [eval exec $binfile &] ++ exec sleep 2 ++ ++ # Verify that we can attach to the process, and find its a.out ++ # when we're cd'd to some directory that doesn't contain the ++ # a.out. (We use the source path set by the "dir" command.) ++ # ++ send_gdb "dir ${objdir}/${subdir}\n" ++ gdb_expect { ++ -re ".*Source directories searched: .*$gdb_prompt $"\ ++ {pass "set source path"} ++ -re "$gdb_prompt $" {fail "set source path"} ++ timeout {fail "(timeout) set source path"} ++ } ++ ++ send_gdb "cd /tmp\n" ++ gdb_expect { ++ -re ".*Working directory /tmp.*$gdb_prompt $"\ ++ {pass "cd away from process' a.out"} ++ -re "$gdb_prompt $" {fail "cd away from process' a.out"} ++ timeout {fail "(timeout) cd away from process' a.out"} ++ } ++ ++ # Explicitly flush out any knowledge of the previous attachment. ++ send_gdb "symbol\n" ++ gdb_expect { ++ -re ".*Discard symbol table from.*y or n. $"\ ++ {send_gdb "y\n" ++ gdb_expect { ++ -re ".*No symbol file now.*$gdb_prompt $"\ ++ {pass "before attach3, flush symbols"} ++ -re "$gdb_prompt $" {fail "before attach3, flush symbols"} ++ timeout {fail "(timeout) before attach3, flush symbols"} ++ } ++ } ++ -re ".*No symbol file now.*$gdb_prompt $"\ ++ {pass "before attach3, flush symbols"} ++ -re "$gdb_prompt $" {fail "before attach3, flush symbols"} ++ timeout {fail "(timeout) before attach3, flush symbols"} ++ } ++ send_gdb "exec\n" ++ gdb_expect { ++ -re ".*No executable file now.*$gdb_prompt $"\ ++ {pass "before attach3, flush exec"} ++ -re "$gdb_prompt $" {fail "before attach3, flush exec"} ++ timeout {fail "(timeout) before attach3, flush exec"} ++ } ++ ++ send_gdb "attach $testpid\n" ++ gdb_expect { ++ -re "Attaching to process $testpid.*Reading symbols from $escapedbinfile.*main.*at .*$gdb_prompt $"\ ++ {pass "attach when process' a.out not in cwd"} ++ -re "$gdb_prompt $" {fail "attach when process' a.out not in cwd"} ++ timeout {fail "(timeout) attach when process' a.out not in cwd"} ++ } ++ ++ send_gdb "kill\n" ++ gdb_expect { ++ -re ".*Kill the program being debugged.*y or n. $"\ ++ {send_gdb "y\n" ++ gdb_expect { ++ -re "$gdb_prompt $" {pass "after attach3, exit"} ++ timeout {fail "(timeout) after attach3, exit"} ++ } ++ } ++ -re "$gdb_prompt $" {fail "after attach3, exit"} ++ timeout {fail "(timeout) after attach3, exit"} ++ } ++ ++ # Another "don't leave a process around" ++ remote_exec build "kill -9 ${testpid}" ++} ++ ++proc do_call_attach_tests {} { ++ global gdb_prompt ++ global binfile2 ++ ++ # Start the program running and then wait for a bit, to be sure ++ # that it can be attached to. ++ # ++ set testpid [eval exec $binfile2 &] ++ exec sleep 2 ++ ++ # Attach ++ # ++ gdb_test "file $binfile2" ".*" "force switch to gdb64, if necessary" ++ send_gdb "attach $testpid\n" ++ gdb_expect { ++ -re ".*warning: reading register.*I.*O error.*$gdb_prompt $" { ++ fail "attach call, read register 3 error" ++ } ++ -re "Attaching to.*process $testpid.*libc.*$gdb_prompt $" { ++ pass "attach call" ++ } ++ -re "$gdb_prompt $" {fail "attach call"} ++ timeout {fail "(timeout) attach call"} ++ } ++ ++ # See if other registers are problems ++ # ++ send_gdb "i r r3\n" ++ gdb_expect { ++ -re ".*warning: reading register.*$gdb_prompt $" { ++ pass "CHFts23490: known bug" ++ } ++ -re ".*r3.*$gdb_prompt $" { ++ pass "Bug fixed, Yayyy!" ++ } ++ timeout { fail "timeout on info reg" } ++ } ++ ++ # Get rid of the process ++ # ++ gdb_test "p should_exit = 1" ".*" ++ gdb_test "c" ".*Program exited normally.*" ++ ++ # Be paranoid ++ # ++ remote_exec build "kill -9 ${testpid}" ++ ++} ++ ++ ++# Start with a fresh gdb ++# ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++# This is a test of gdb's ability to attach to a running process. ++# ++do_attach_tests ++ ++# Test attaching when the target is inside a system call ++# ++gdb_exit ++gdb_start ++ ++gdb_reinitialize_dir $srcdir/$subdir ++do_call_attach_tests ++ ++return 0 +Index: gdb-6.8.50.20081128/gdb/testsuite/gdb.pie/break.exp +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8.50.20081128/gdb/testsuite/gdb.pie/break.exp 2008-12-09 17:24:34.000000000 +0100 +@@ -0,0 +1,973 @@ ++# Copyright 1988, 1990, 1991, 1992, 1994, 1995, 1996, 1997, 1998, 1999, ++# 2000, 2002, 2003, 2004 ++# Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++# Please email any bugs, comments, and/or additions to this file to: ++# bug-gdb@prep.ai.mit.edu ++ ++# This file was written by Rob Savoye. (rob@cygnus.com) ++ ++# Test the same stuff but with PIE executables ++ ++if $tracelevel then { ++ strace $tracelevel ++} ++ ++ ++# ++# test running programs ++# ++set prms_id 0 ++set bug_id 0 ++ ++set testfile "break" ++set srcfile ${testfile}.c ++set srcfile1 ${testfile}1.c ++set binfile ${objdir}/${subdir}/${testfile} ++ ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}0.o" object {debug "additional_flags=-w -fpie -pie"}] != "" } { ++ gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail." ++} ++ ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile1}" "${binfile}1.o" object {debug "additional_flags=-w -fpie -pie"}] != "" } { ++ gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail." ++} ++ ++if { [gdb_compile "${binfile}0.o ${binfile}1.o" "${binfile}" executable {debug "additional_flags=-w -fpie -pie"}] != "" } { ++ gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail." ++} ++ ++if [get_compiler_info ${binfile}] { ++ return -1 ++} ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++if [target_info exists gdb_stub] { ++ gdb_step_for_stub; ++} ++# ++# test simple breakpoint setting commands ++# ++ ++# Test deleting all breakpoints when there are none installed, ++# GDB should not prompt for confirmation. ++# Note that gdb-init.exp provides a "delete_breakpoints" proc ++# for general use elsewhere. ++ ++send_gdb "delete breakpoints\n" ++gdb_expect { ++ -re "Delete all breakpoints.*$" { ++ send_gdb "y\n" ++ gdb_expect { ++ -re "$gdb_prompt $" { ++ fail "Delete all breakpoints when none (unexpected prompt)" ++ } ++ timeout { fail "Delete all breakpoints when none (timeout after unexpected prompt)" } ++ } ++ } ++ -re ".*$gdb_prompt $" { pass "Delete all breakpoints when none" } ++ timeout { fail "Delete all breakpoints when none (timeout)" } ++} ++ ++# ++# test break at function ++# ++gdb_test "break main" \ ++ "Breakpoint.*at.* file .*$srcfile, line.*" \ ++ "breakpoint function" ++ ++# ++# test break at quoted function ++# ++gdb_test "break \"marker2\"" \ ++ "Breakpoint.*at.* file .*$srcfile1, line.*" \ ++ "breakpoint quoted function" ++ ++# ++# test break at function in file ++# ++gdb_test "break $srcfile:factorial" \ ++ "Breakpoint.*at.* file .*$srcfile, line.*" \ ++ "breakpoint function in file" ++ ++set bp_location1 [gdb_get_line_number "set breakpoint 1 here"] ++ ++# ++# test break at line number ++# ++# Note that the default source file is the last one whose source text ++# was printed. For native debugging, before we've executed the ++# program, this is the file containing main, but for remote debugging, ++# it's wherever the processor was stopped when we connected to the ++# board. So, to be sure, we do a list command. ++# ++gdb_test "list main" \ ++ ".*main \\(argc, argv, envp\\).*" \ ++ "use `list' to establish default source file" ++gdb_test "break $bp_location1" \ ++ "Breakpoint.*at.* file .*$srcfile, line $bp_location1\\." \ ++ "breakpoint line number" ++ ++# ++# test duplicate breakpoint ++# ++gdb_test "break $bp_location1" \ ++ "Note: breakpoint \[0-9\]+ also set at pc.*Breakpoint \[0-9\]+ at.* file .*$srcfile, line $bp_location1\\." \ ++ "breakpoint duplicate" ++ ++set bp_location2 [gdb_get_line_number "set breakpoint 2 here"] ++ ++# ++# test break at line number in file ++# ++gdb_test "break $srcfile:$bp_location2" \ ++ "Breakpoint.*at.* file .*$srcfile, line $bp_location2\\." \ ++ "breakpoint line number in file" ++ ++set bp_location3 [gdb_get_line_number "set breakpoint 3 here"] ++set bp_location4 [gdb_get_line_number "set breakpoint 4 here"] ++ ++# ++# Test putting a break at the start of a multi-line if conditional. ++# Verify the breakpoint was put at the start of the conditional. ++# ++gdb_test "break multi_line_if_conditional" \ ++ "Breakpoint.*at.* file .*$srcfile, line $bp_location3\\." \ ++ "breakpoint at start of multi line if conditional" ++ ++gdb_test "break multi_line_while_conditional" \ ++ "Breakpoint.*at.* file .*$srcfile, line $bp_location4\\." \ ++ "breakpoint at start of multi line while conditional" ++ ++set bp_location5 [gdb_get_line_number "set breakpoint 5 here"] ++set bp_location6 [gdb_get_line_number "set breakpoint 6 here"] ++ ++# ++# check to see what breakpoints are set ++# ++if [target_info exists gdb_stub] { ++ set main_line $bp_location5 ++} else { ++ set main_line $bp_location6 ++} ++ ++if {$hp_aCC_compiler} { ++ set proto "\\(int\\)" ++} else { ++ set proto "" ++} ++ ++set bp_location7 [gdb_get_line_number "set breakpoint 7 here"] ++set bp_location8 [gdb_get_line_number "set breakpoint 8 here" $srcfile1] ++set bp_location9 [gdb_get_line_number "set breakpoint 9 here" $srcfile1] ++ ++gdb_test "info break" \ ++ "Num\[ \]+Type\[ \]+Disp Enb Address\[ \]+What.* ++\[0-9\]+\[\t \]+breakpoint keep y.* in main at .*$srcfile:$main_line.* ++\[0-9\]+\[\t \]+breakpoint keep y.* in marker2 at .*$srcfile1:($bp_location8|$bp_location9).* ++\[0-9\]+\[\t \]+breakpoint keep y.* in factorial$proto at .*$srcfile:$bp_location7.* ++\[0-9\]+\[\t \]+breakpoint keep y.* in main at .*$srcfile:$bp_location1.* ++\[0-9\]+\[\t \]+breakpoint keep y.* in main at .*$srcfile:$bp_location1.* ++\[0-9\]+\[\t \]+breakpoint keep y.* in main at .*$srcfile:$bp_location2.* ++\[0-9\]+\[\t \]+breakpoint keep y.* in multi_line_if_conditional at .*$srcfile:$bp_location3.* ++\[0-9\]+\[\t \]+breakpoint keep y.* in multi_line_while_conditional at .*$srcfile:$bp_location4" \ ++ "breakpoint info" ++ ++# FIXME: The rest of this test doesn't work with anything that can't ++# handle arguments. ++# Huh? There doesn't *appear* to be anything that passes arguments ++# below. ++if [istarget "mips-idt-*"] then { ++ return ++} ++ ++# ++# run until the breakpoint at main is hit. For non-stubs-using targets. ++# ++if ![target_info exists use_gdb_stub] { ++ if [istarget "*-*-vxworks*"] then { ++ send_gdb "run vxmain \"2\"\n" ++ set timeout 120 ++ verbose "Timeout is now $timeout seconds" 2 ++ } else { ++ send_gdb "run\n" ++ } ++ gdb_expect { ++ -re "The program .* has been started already.*y or n. $" { ++ send_gdb "y\n" ++ exp_continue ++ } ++ -re "Starting program.*Breakpoint \[0-9\]+,.*main .*argc.*argv.* at .*$srcfile:$bp_location6.*$bp_location6\[\t \]+if .argc.* \{.*$gdb_prompt $"\ ++ { pass "run until function breakpoint" } ++ -re ".*$gdb_prompt $" { fail "run until function breakpoint" } ++ timeout { fail "run until function breakpoint (timeout)" } ++ } ++} else { ++ if ![target_info exists gdb_stub] { ++ gdb_test continue ".*Continuing\\..*Breakpoint \[0-9\]+, main \\(argc=.*, argv=.*, envp=.*\\) at .*$srcfile:$bp_location6.*$bp_location6\[\t \]+if .argc.*\{.*" "stub continue" ++ } ++} ++ ++# ++# run until the breakpoint at a line number ++# ++gdb_test continue "Continuing\\..*Breakpoint \[0-9\]+, main \\(argc=.*, argv=.*, envp=.*\\) at .*$srcfile:$bp_location1.*$bp_location1\[\t \]+printf.*factorial.*" \ ++ "run until breakpoint set at a line number" ++ ++# ++# Run until the breakpoint set in a function in a file ++# ++for {set i 6} {$i >= 1} {incr i -1} { ++ gdb_test continue "Continuing\\..*Breakpoint \[0-9\]+, factorial \\(value=$i\\) at .*$srcfile:$bp_location7.*$bp_location7\[\t \]+.*if .value > 1. \{.*" \ ++ "run until file:function($i) breakpoint" ++} ++ ++# ++# Run until the breakpoint set at a quoted function ++# ++gdb_test continue "Continuing\\..*Breakpoint \[0-9\]+, (0x\[0-9a-f\]+ in )?marker2 \\(a=43\\) at .*$srcfile1:($bp_location8|$bp_location9).*" \ ++ "run until quoted breakpoint" ++# ++# run until the file:function breakpoint at a line number in a file ++# ++gdb_test continue "Continuing\\..*Breakpoint \[0-9\]+, main \\(argc=.*, argv=.*, envp=.*\\) at .*$srcfile:$bp_location2.*$bp_location2\[\t \]+argc = \\(argc == 12345\\);.*" \ ++ "run until file:linenum breakpoint" ++ ++# Test break at offset +1 ++set bp_location10 [gdb_get_line_number "set breakpoint 10 here"] ++ ++gdb_test "break +1" \ ++ "Breakpoint.*at.* file .*$srcfile, line $bp_location10\\." \ ++ "breakpoint offset +1" ++ ++# Check to see if breakpoint is hit when stepped onto ++ ++gdb_test "step" \ ++ ".*Breakpoint \[0-9\]+, main \\(argc=.*, argv=.*, envp=.*\\) at .*$srcfile:$bp_location10.*$bp_location10\[\t \]+return argc;.*breakpoint 10 here.*" \ ++ "step onto breakpoint" ++ ++# ++# delete all breakpoints so we can start over, course this can be a test too ++# ++delete_breakpoints ++ ++# ++# test temporary breakpoint at function ++# ++ ++gdb_test "tbreak main" "reakpoint.*at.* file .*$srcfile, line.*" "Temporary breakpoint function" ++ ++# ++# test break at function in file ++# ++ ++gdb_test "tbreak $srcfile:factorial" "reakpoint.*at.* file .*$srcfile, line.*" \ ++ "Temporary breakpoint function in file" ++ ++# ++# test break at line number ++# ++send_gdb "tbreak $bp_location1\n" ++gdb_expect { ++ -re "reakpoint.*at.* file .*$srcfile, line $bp_location1.*$gdb_prompt $" { pass "Temporary breakpoint line number #1" } ++ -re ".*$gdb_prompt $" { pass "Temporary breakpoint line number #1" } ++ timeout { fail "breakpoint line number #1 (timeout)" } ++} ++ ++gdb_test "tbreak $bp_location6" "reakpoint.*at.* file .*$srcfile, line $bp_location6.*" "Temporary breakpoint line number #2" ++ ++# ++# test break at line number in file ++# ++send_gdb "tbreak $srcfile:$bp_location2\n" ++gdb_expect { ++ -re "reakpoint.*at.* file .*$srcfile, line $bp_location2.*$gdb_prompt $" { pass "Temporary breakpoint line number in file #1" } ++ -re ".*$gdb_prompt $" { pass "Temporary breakpoint line number in file #1" } ++ timeout { fail "Temporary breakpoint line number in file #1 (timeout)" } ++} ++ ++set bp_location11 [gdb_get_line_number "set breakpoint 11 here"] ++gdb_test "tbreak $srcfile:$bp_location11" "reakpoint.*at.* file .*$srcfile, line $bp_location11.*" "Temporary breakpoint line number in file #2" ++ ++# ++# check to see what breakpoints are set (temporary this time) ++# ++gdb_test "info break" "Num.*Type.*Disp Enb Address.*What.*\[\r\n\] ++\[0-9\]+\[\t \]+breakpoint del.*y.*in main at .*$srcfile:$main_line.*\[\r\n\] ++\[0-9\]+\[\t \]+breakpoint del.*y.*in factorial$proto at .*$srcfile:$bp_location7.*\[\r\n\] ++\[0-9\]+\[\t \]+breakpoint del.*y.*in main at .*$srcfile:$bp_location1.*\[\r\n\] ++\[0-9\]+\[\t \]+breakpoint del.*y.*in main at .*$srcfile:$bp_location6.*\[\r\n\] ++\[0-9\]+\[\t \]+breakpoint del.*y.*in main at .*$srcfile:$bp_location2.*\[\r\n\] ++\[0-9\]+\[\t \]+breakpoint del.*y.*in main at .*$srcfile:$bp_location11.*" \ ++ "Temporary breakpoint info" ++ ++ ++#*********** ++ ++# Verify that catchpoints for fork, vfork and exec don't trigger ++# inappropriately. (There are no calls to those system functions ++# in this test program.) ++# ++if ![runto_main] then { fail "break tests suppressed" } ++ ++send_gdb "catch\n" ++gdb_expect { ++ -re "Catch requires an event name.*$gdb_prompt $"\ ++ {pass "catch requires an event name"} ++ -re "$gdb_prompt $"\ ++ {fail "catch requires an event name"} ++ timeout {fail "(timeout) catch requires an event name"} ++} ++ ++ ++set name "set catch fork, never expected to trigger" ++send_gdb "catch fork\n" ++gdb_expect { ++ -re "Catchpoint \[0-9\]* .fork..*$gdb_prompt $" ++ {pass $name} ++ -re "Catch of fork not yet implemented.*$gdb_prompt $" ++ {pass $name} ++ -re "$gdb_prompt $" ++ {fail $name} ++ timeout {fail "(timeout) $name"} ++} ++ ++ ++set name "set catch vfork, never expected to trigger" ++send_gdb "catch vfork\n" ++ ++# If we are on HP-UX 10.20, we expect an error message to be ++# printed if we type "catch vfork" at the gdb gdb_prompt. This is ++# because on HP-UX 10.20, we cannot catch vfork events. ++ ++if [istarget "hppa*-hp-hpux10.20"] then { ++ gdb_expect { ++ -re "Catch of vfork events not supported on HP-UX 10.20..*$gdb_prompt $" ++ {pass $name} ++ -re "$gdb_prompt $" ++ {fail $name} ++ timeout {fail "(timeout) $name"} ++ } ++} else { ++ gdb_expect { ++ -re "Catchpoint \[0-9\]* .vfork..*$gdb_prompt $" ++ {pass $name} ++ -re "Catch of vfork not yet implemented.*$gdb_prompt $" ++ {pass $name} ++ -re "$gdb_prompt $" ++ {fail $name} ++ timeout {fail "(timeout) $name"} ++ } ++} ++ ++set name "set catch exec, never expected to trigger" ++send_gdb "catch exec\n" ++gdb_expect { ++ -re "Catchpoint \[0-9\]* .exec..*$gdb_prompt $" ++ {pass $name} ++ -re "Catch of exec not yet implemented.*$gdb_prompt $" ++ {pass $name} ++ -re "$gdb_prompt $" {fail $name} ++ timeout {fail "(timeout) $name"} ++} ++ ++# Verify that GDB responds gracefully when asked to set a breakpoint ++# on a nonexistent source line. ++# ++send_gdb "break 999\n" ++gdb_expect { ++ -re "No line 999 in file .*$gdb_prompt $"\ ++ {pass "break on non-existent source line"} ++ -re "$gdb_prompt $"\ ++ {fail "break on non-existent source line"} ++ timeout {fail "(timeout) break on non-existent source line"} ++} ++ ++# Run to the desired default location. If not positioned here, the ++# tests below don't work. ++# ++gdb_test "until $bp_location1" "main .* at .*:$bp_location1.*" "until bp_location1" ++ ++ ++# Verify that GDB allows one to just say "break", which is treated ++# as the "default" breakpoint. Note that GDB gets cute when printing ++# the informational message about other breakpoints at the same ++# location. We'll hit that bird with this stone too. ++# ++send_gdb "break\n" ++gdb_expect { ++ -re "Breakpoint \[0-9\]*.*$gdb_prompt $"\ ++ {pass "break on default location, 1st time"} ++ -re "$gdb_prompt $"\ ++ {fail "break on default location, 1st time"} ++ timeout {fail "(timeout) break on default location, 1st time"} ++} ++ ++send_gdb "break\n" ++gdb_expect { ++ -re "Note: breakpoint \[0-9\]* also set at .*Breakpoint \[0-9\]*.*$gdb_prompt $"\ ++ {pass "break on default location, 2nd time"} ++ -re "$gdb_prompt $"\ ++ {fail "break on default location, 2nd time"} ++ timeout {fail "(timeout) break on default location, 2nd time"} ++} ++ ++send_gdb "break\n" ++gdb_expect { ++ -re "Note: breakpoints \[0-9\]* and \[0-9\]* also set at .*Breakpoint \[0-9\]*.*$gdb_prompt $"\ ++ {pass "break on default location, 3rd time"} ++ -re "$gdb_prompt $"\ ++ {fail "break on default location, 3rd time"} ++ timeout {fail "(timeout) break on default location, 3rd time"} ++} ++ ++send_gdb "break\n" ++gdb_expect { ++ -re "Note: breakpoints \[0-9\]*, \[0-9\]* and \[0-9\]* also set at .*Breakpoint \[0-9\]*.*$gdb_prompt $"\ ++ {pass "break on default location, 4th time"} ++ -re "$gdb_prompt $"\ ++ {fail "break on default location, 4th time"} ++ timeout {fail "(timeout) break on default location, 4th time"} ++} ++ ++# Verify that a "silent" breakpoint can be set, and that GDB is indeed ++# "silent" about its triggering. ++# ++if ![runto_main] then { fail "break tests suppressed" } ++ ++send_gdb "break $bp_location1\n" ++gdb_expect { ++ -re "Breakpoint (\[0-9\]*) at .*, line $bp_location1.*$gdb_prompt $"\ ++ {pass "set to-be-silent break bp_location1"} ++ -re "$gdb_prompt $"\ ++ {fail "set to-be-silent break bp_location1"} ++ timeout {fail "(timeout) set to-be-silent break bp_location1"} ++} ++ ++send_gdb "commands $expect_out(1,string)\n" ++send_gdb "silent\n" ++send_gdb "end\n" ++gdb_expect { ++ -re ".*$gdb_prompt $"\ ++ {pass "set silent break bp_location1"} ++ timeout {fail "(timeout) set silent break bp_location1"} ++} ++ ++send_gdb "info break $expect_out(1,string)\n" ++gdb_expect { ++ -re "\[0-9\]*\[ \t\]*breakpoint.*:$bp_location1\r\n\[ \t\]*silent.*$gdb_prompt $"\ ++ {pass "info silent break bp_location1"} ++ -re "$gdb_prompt $"\ ++ {fail "info silent break bp_location1"} ++ timeout {fail "(timeout) info silent break bp_location1"} ++} ++send_gdb "continue\n" ++gdb_expect { ++ -re "Continuing.\r\n$gdb_prompt $"\ ++ {pass "hit silent break bp_location1"} ++ -re "$gdb_prompt $"\ ++ {fail "hit silent break bp_location1"} ++ timeout {fail "(timeout) hit silent break bp_location1"} ++} ++send_gdb "bt\n" ++gdb_expect { ++ -re "#0 main .* at .*:$bp_location1.*$gdb_prompt $"\ ++ {pass "stopped for silent break bp_location1"} ++ -re "$gdb_prompt $"\ ++ {fail "stopped for silent break bp_location1"} ++ timeout {fail "(timeout) stopped for silent break bp_location1"} ++} ++ ++# Verify that GDB can at least parse a breakpoint with the ++# "thread" keyword. (We won't attempt to test here that a ++# thread-specific breakpoint really triggers appropriately. ++# The gdb.threads subdirectory contains tests for that.) ++# ++set bp_location12 [gdb_get_line_number "set breakpoint 12 here"] ++send_gdb "break $bp_location12 thread 999\n" ++gdb_expect { ++ -re "Unknown thread 999.*$gdb_prompt $"\ ++ {pass "thread-specific breakpoint on non-existent thread disallowed"} ++ -re "$gdb_prompt $"\ ++ {fail "thread-specific breakpoint on non-existent thread disallowed"} ++ timeout {fail "(timeout) thread-specific breakpoint on non-existent thread disallowed"} ++} ++send_gdb "break $bp_location12 thread foo\n" ++gdb_expect { ++ -re "Junk after thread keyword..*$gdb_prompt $"\ ++ {pass "thread-specific breakpoint on bogus thread ID disallowed"} ++ -re "$gdb_prompt $"\ ++ {fail "thread-specific breakpoint on bogus thread ID disallowed"} ++ timeout {fail "(timeout) thread-specific breakpoint on bogus thread ID disallowed"} ++} ++ ++# Verify that GDB responds gracefully to a breakpoint command with ++# trailing garbage. ++# ++send_gdb "break $bp_location12 foo\n" ++gdb_expect { ++ -re "Junk at end of arguments..*$gdb_prompt $"\ ++ {pass "breakpoint with trailing garbage disallowed"} ++ -re "$gdb_prompt $"\ ++ {fail "breakpoint with trailing garbage disallowed"} ++ timeout {fail "(timeout) breakpoint with trailing garbage disallowed"} ++} ++ ++# Verify that GDB responds gracefully to a "clear" command that has ++# no matching breakpoint. (First, get us off the current source line, ++# which we know has a breakpoint.) ++# ++send_gdb "next\n" ++gdb_expect { ++ -re ".*$gdb_prompt $"\ ++ {pass "step over breakpoint"} ++ timeout {fail "(timeout) step over breakpoint"} ++} ++send_gdb "clear 81\n" ++gdb_expect { ++ -re "No breakpoint at 81..*$gdb_prompt $"\ ++ {pass "clear line has no breakpoint disallowed"} ++ -re "$gdb_prompt $"\ ++ {fail "clear line has no breakpoint disallowed"} ++ timeout {fail "(timeout) clear line has no breakpoint disallowed"} ++} ++send_gdb "clear\n" ++gdb_expect { ++ -re "No breakpoint at this line..*$gdb_prompt $"\ ++ {pass "clear current line has no breakpoint disallowed"} ++ -re "$gdb_prompt $"\ ++ {fail "clear current line has no breakpoint disallowed"} ++ timeout {fail "(timeout) clear current line has no breakpoint disallowed"} ++} ++ ++# Verify that we can set and clear multiple breakpoints. ++# ++# We don't test that it deletes the correct breakpoints. We do at ++# least test that it deletes more than one breakpoint. ++# ++gdb_test "break marker3" "Breakpoint.*at.*" "break marker3 #1" ++gdb_test "break marker3" "Breakpoint.*at.*" "break marker3 #2" ++gdb_test "clear marker3" {Deleted breakpoints [0-9]+ [0-9]+.*} ++ ++# Verify that a breakpoint can be set via a convenience variable. ++# ++send_gdb "set \$foo=$bp_location11\n" ++gdb_expect { ++ -re "$gdb_prompt $"\ ++ {pass "set convenience variable \$foo to bp_location11"} ++ timeout {fail "(timeout) set convenience variable \$foo to bp_location11"} ++} ++send_gdb "break \$foo\n" ++gdb_expect { ++ -re "Breakpoint (\[0-9\]*) at .*, line $bp_location11.*$gdb_prompt $"\ ++ {pass "set breakpoint via convenience variable"} ++ -re "$gdb_prompt $"\ ++ {fail "set breakpoint via convenience variable"} ++ timeout {fail "(timeout) set breakpoint via convenience variable"} ++} ++ ++# Verify that GDB responds gracefully to an attempt to set a ++# breakpoint via a convenience variable whose type is not integer. ++# ++send_gdb "set \$foo=81.5\n" ++gdb_expect { ++ -re "$gdb_prompt $"\ ++ {pass "set convenience variable \$foo to 81.5"} ++ timeout {fail "(timeout) set convenience variable \$foo to 81.5"} ++} ++send_gdb "break \$foo\n" ++gdb_expect { ++ -re "Convenience variables used in line specs must have integer values..*$gdb_prompt $"\ ++ {pass "set breakpoint via non-integer convenience variable disallowed"} ++ -re "$gdb_prompt $"\ ++ {fail "set breakpoint via non-integer convenience variable disallowed"} ++ timeout {fail "(timeout) set breakpoint via non-integer convenience variable disallowed"} ++} ++ ++# Verify that we can set and trigger a breakpoint in a user-called function. ++# ++send_gdb "break marker2\n" ++gdb_expect { ++ -re "Breakpoint (\[0-9\]*) at .*, line ($bp_location8|$bp_location9).*$gdb_prompt $"\ ++ {pass "set breakpoint on to-be-called function"} ++ -re "$gdb_prompt $"\ ++ {fail "set breakpoint on to-be-called function"} ++ timeout {fail "(timeout) set breakpoint on to-be-called function"} ++} ++send_gdb "print marker2(99)\n" ++gdb_expect { ++ -re "The program being debugged stopped while in a function called from GDB.\r\nWhen the function .marker2$proto. is done executing, GDB will silently\r\nstop .instead of continuing to evaluate the expression containing\r\nthe function call...*$gdb_prompt $"\ ++ {pass "hit breakpoint on called function"} ++ -re "$gdb_prompt $"\ ++ {fail "hit breakpoint on called function"} ++ timeout {fail "(timeout) hit breakpoint on called function"} ++} ++ ++# As long as we're stopped (breakpointed) in a called function, ++# verify that we can successfully backtrace & such from here. ++# ++# In this and the following test, the _sr4export check apparently is needed ++# for hppa*-*-hpux. ++# ++send_gdb "bt\n" ++gdb_expect { ++ -re "#0\[ \t\]*($hex in )?marker2.*:($bp_location8|$bp_location9)\r\n#1.*_sr4export.*$gdb_prompt $"\ ++ {pass "backtrace while in called function"} ++ -re "#0\[ \t\]*($hex in )?marker2.*:($bp_location8|$bp_location9)\r\n#1.*function called from gdb.*$gdb_prompt $"\ ++ {pass "backtrace while in called function"} ++ -re "$gdb_prompt $"\ ++ {fail "backtrace while in called function"} ++ timeout {fail "(timeout) backtrace while in called function"} ++} ++ ++# Return from the called function. For remote targets, it's important to do ++# this before runto_main, which otherwise may silently stop on the dummy ++# breakpoint inserted by GDB at the program's entry point. ++# ++send_gdb "finish\n" ++gdb_expect { ++ -re "Run till exit from .*marker2.* at .*($bp_location8|$bp_location9)\r\n.* in _sr4export.*$gdb_prompt $"\ ++ {pass "finish from called function"} ++ -re "Run till exit from .*marker2.* at .*($bp_location8|$bp_location9)\r\n.*function called from gdb.*$gdb_prompt $"\ ++ {pass "finish from called function"} ++ -re "Run till exit from .*marker2.* at .*($bp_location8|$bp_location9)\r\n.*Value returned.*$gdb_prompt $"\ ++ {pass "finish from called function"} ++ -re "$gdb_prompt $"\ ++ {fail "finish from called function"} ++ timeout {fail "(timeout) finish from called function"} ++} ++ ++# Verify that GDB responds gracefully to a "finish" command with ++# arguments. ++# ++if ![runto_main] then { fail "break tests suppressed" } ++ ++send_gdb "finish 123\n" ++gdb_expect { ++ -re "The \"finish\" command does not take any arguments.\r\n$gdb_prompt $"\ ++ {pass "finish with arguments disallowed"} ++ -re "$gdb_prompt $"\ ++ {fail "finish with arguments disallowed"} ++ timeout {fail "(timeout) finish with arguments disallowed"} ++} ++ ++# Verify that GDB responds gracefully to a request to "finish" from ++# the outermost frame. On a stub that never exits, this will just ++# run to the stubs routine, so we don't get this error... Thus the ++# second condition. ++# ++ ++send_gdb "finish\n" ++gdb_expect { ++ -re "\"finish\" not meaningful in the outermost frame.\r\n$gdb_prompt $"\ ++ {pass "finish from outermost frame disallowed"} ++ -re "Run till exit from.*\r\n$gdb_prompt $" { ++ pass "finish from outermost frame disallowed" ++ } ++ -re "$gdb_prompt $"\ ++ {fail "finish from outermost frame disallowed"} ++ timeout {fail "(timeout) finish from outermost frame disallowed"} ++} ++ ++# Verify that we can explicitly ask GDB to stop on all shared library ++# events, and that it does so. ++# ++if [istarget "hppa*-*-hpux*"] then { ++ if ![runto_main] then { fail "break tests suppressed" } ++ ++ send_gdb "set stop-on-solib-events 1\n" ++ gdb_expect { ++ -re "$gdb_prompt $"\ ++ {pass "set stop-on-solib-events"} ++ timeout {fail "(timeout) set stop-on-solib-events"} ++ } ++ ++ send_gdb "run\n" ++ gdb_expect { ++ -re ".*Start it from the beginning.*y or n. $"\ ++ {send_gdb "y\n" ++ gdb_expect { ++ -re ".*Stopped due to shared library event.*$gdb_prompt $"\ ++ {pass "triggered stop-on-solib-events"} ++ -re "$gdb_prompt $"\ ++ {fail "triggered stop-on-solib-events"} ++ timeout {fail "(timeout) triggered stop-on-solib-events"} ++ } ++ } ++ -re "$gdb_prompt $"\ ++ {fail "rerun for stop-on-solib-events"} ++ timeout {fail "(timeout) rerun for stop-on-solib-events"} ++ } ++ ++ send_gdb "set stop-on-solib-events 0\n" ++ gdb_expect { ++ -re "$gdb_prompt $"\ ++ {pass "reset stop-on-solib-events"} ++ timeout {fail "(timeout) reset stop-on-solib-events"} ++ } ++} ++ ++# Hardware breakpoints are unsupported on HP-UX. Verify that GDB ++# gracefully responds to requests to create them. ++# ++if [istarget "hppa*-*-hpux*"] then { ++ if ![runto_main] then { fail "break tests suppressed" } ++ ++ send_gdb "hbreak\n" ++ gdb_expect { ++ -re "No hardware breakpoint support in the target.*$gdb_prompt $"\ ++ {pass "hw breaks disallowed"} ++ -re "$gdb_prompt $"\ ++ {fail "hw breaks disallowed"} ++ timeout {fail "(timeout) hw breaks disallowed"} ++ } ++ ++ send_gdb "thbreak\n" ++ gdb_expect { ++ -re "No hardware breakpoint support in the target.*$gdb_prompt $"\ ++ {pass "temporary hw breaks disallowed"} ++ -re "$gdb_prompt $"\ ++ {fail "temporary hw breaks disallowed"} ++ timeout {fail "(timeout) temporary hw breaks disallowed"} ++ } ++} ++ ++#******** ++ ++ ++# ++# Test "next" over recursive function call. ++# ++ ++proc test_next_with_recursion {} { ++ global gdb_prompt ++ global decimal ++ global binfile ++ ++ if [target_info exists use_gdb_stub] { ++ # Reload the program. ++ delete_breakpoints ++ gdb_load ${binfile}; ++ } else { ++ # FIXME: should be using runto ++ gdb_test "kill" "" "kill program" "Kill the program being debugged.*y or n. $" "y" ++ ++ delete_breakpoints ++ } ++ ++ gdb_test "break factorial" "Breakpoint $decimal at .*" "break at factorial" ++ ++ # Run until we call factorial with 6 ++ ++ if [istarget "*-*-vxworks*"] then { ++ send_gdb "run vxmain \"6\"\n" ++ } else { ++ gdb_run_cmd ++ } ++ gdb_expect { ++ -re "Break.* factorial .value=6. .*$gdb_prompt $" {} ++ -re ".*$gdb_prompt $" { ++ fail "run to factorial(6)"; ++ gdb_suppress_tests; ++ } ++ timeout { fail "run to factorial(6) (timeout)" ; gdb_suppress_tests } ++ } ++ ++ # Continue until we call factorial recursively with 5. ++ ++ if [gdb_test "continue" \ ++ "Continuing.*Break.* factorial .value=5. .*" \ ++ "continue to factorial(5)"] then { gdb_suppress_tests } ++ ++ # Do a backtrace just to confirm how many levels deep we are. ++ ++ if [gdb_test "backtrace" \ ++ "#0\[ \t\]+ factorial .value=5..*" \ ++ "backtrace from factorial(5)"] then { gdb_suppress_tests } ++ ++ # Now a "next" should position us at the recursive call, which ++ # we will be performing with 4. ++ ++ if [gdb_test "next" \ ++ ".* factorial .value - 1.;.*" \ ++ "next to recursive call"] then { gdb_suppress_tests } ++ ++ # Disable the breakpoint at the entry to factorial by deleting them all. ++ # The "next" should run until we return to the next line from this ++ # recursive call to factorial with 4. ++ # Buggy versions of gdb will stop instead at the innermost frame on ++ # the line where we are trying to "next" to. ++ ++ delete_breakpoints ++ ++ if [istarget "mips*tx39-*"] { ++ set timeout 60 ++ } ++ # We used to set timeout here for all other targets as well. This ++ # is almost certainly wrong. The proper timeout depends on the ++ # target system in use, and how we communicate with it, so there ++ # is no single value appropriate for all targets. The timeout ++ # should be established by the Dejagnu config file(s) for the ++ # board, and respected by the test suite. ++ # ++ # For example, if I'm running GDB over an SSH tunnel talking to a ++ # portmaster in California talking to an ancient 68k board running ++ # a crummy ROM monitor (a situation I can only wish were ++ # hypothetical), then I need a large timeout. But that's not the ++ # kind of knowledge that belongs in this file. ++ ++ gdb_test next "\[0-9\]*\[\t \]+return \\(value\\);.*" \ ++ "next over recursive call" ++ ++ # OK, we should be back in the same stack frame we started from. ++ # Do a backtrace just to confirm. ++ ++ set result [gdb_test "backtrace" \ ++ "#0\[ \t\]+ factorial .value=120.*\r\n#1\[ \t\]+ \[0-9a-fx\]+ in factorial .value=6..*" \ ++ "backtrace from factorial(5.1)"] ++ if { $result != 0 } { gdb_suppress_tests } ++ ++ if [target_info exists gdb,noresults] { gdb_suppress_tests } ++ gdb_continue_to_end "recursive next test" ++ gdb_stop_suppressing_tests; ++} ++ ++test_next_with_recursion ++ ++ ++#******** ++ ++# build a new file with optimization enabled so that we can try breakpoints ++# on targets with optimized prologues ++ ++set binfileo2 ${objdir}/${subdir}/${testfile}o2 ++ ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}O0.o" object {debug "additional_flags=-w -O2 -fpie -pie"}] != "" } { ++ gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail." ++} ++ ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile1}" "${binfile}O1.o" object {debug "additional_flags=-w -O2 -fpie -pie"}] != "" } { ++ gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail." ++} ++ ++if { [gdb_compile "${binfile}O0.o ${binfile}O1.o" "${binfileo2}" executable {debug "additional_flags=-w -fpie -pie"}] != "" } { ++ gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail." ++} ++ ++if [get_compiler_info ${binfileo2}] { ++ return -1 ++} ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfileo2} ++ ++if [target_info exists gdb_stub] { ++ gdb_step_for_stub; ++} ++ ++# ++# test break at function ++# ++gdb_test "break main" \ ++ "Breakpoint.*at.* file .*$srcfile, line.*" \ ++ "breakpoint function, optimized file" ++ ++# ++# test break at function ++# ++gdb_test "break marker4" \ ++ "Breakpoint.*at.* file .*$srcfile1, line.*" \ ++ "breakpoint small function, optimized file" ++ ++# ++# run until the breakpoint at main is hit. For non-stubs-using targets. ++# ++if ![target_info exists use_gdb_stub] { ++ if [istarget "*-*-vxworks*"] then { ++ send_gdb "run vxmain \"2\"\n" ++ set timeout 120 ++ verbose "Timeout is now $timeout seconds" 2 ++ } else { ++ send_gdb "run\n" ++ } ++ gdb_expect { ++ -re "The program .* has been started already.*y or n. $" { ++ send_gdb "y\n" ++ exp_continue ++ } ++ -re "Starting program.*Breakpoint \[0-9\]+,.*main .*argc.*argv.* at .*$srcfile:$bp_location6.*$bp_location6\[\t \]+if .argc.* \{.*$gdb_prompt $"\ ++ { pass "run until function breakpoint, optimized file" } ++ -re "Starting program.*Breakpoint \[0-9\]+,.*main .*argc.*argv.* at .*$gdb_prompt $"\ ++ { pass "run until function breakpoint, optimized file (code motion)" } ++ -re ".*$gdb_prompt $" { fail "run until function breakpoint, optimized file" } ++ timeout { fail "run until function breakpoint, optimized file (timeout)" } ++ } ++} else { ++ if ![target_info exists gdb_stub] { ++ gdb_test continue ".*Continuing\\..*Breakpoint \[0-9\]+, main \\(argc=.*, argv=.*, envp=.*\\) at .*$srcfile:$bp_location6.*$bp_location6\[\t \]+if .argc.*\{.*" "stub continue, optimized file" ++ } ++} ++ ++# ++# run until the breakpoint at a small function ++# ++ ++# ++# Add a second pass pattern. The behavior differs here between stabs ++# and dwarf for one-line functions. Stabs preserves two line symbols ++# (one before the prologue and one after) with the same line number, ++# but dwarf regards these as duplicates and discards one of them. ++# Therefore the address after the prologue (where the breakpoint is) ++# has no exactly matching line symbol, and GDB reports the breakpoint ++# as if it were in the middle of a line rather than at the beginning. ++ ++set bp_location13 [gdb_get_line_number "set breakpoint 13 here" $srcfile1] ++set bp_location14 [gdb_get_line_number "set breakpoint 14 here" $srcfile1] ++send_gdb "continue\n" ++gdb_expect { ++ -re "Breakpoint $decimal, marker4 \\(d=177601976\\) at .*$srcfile1:$bp_location13\[\r\n\]+$bp_location13\[\t \]+void marker4.*" { ++ pass "run until breakpoint set at small function, optimized file" ++ } ++ -re "Breakpoint $decimal, $hex in marker4 \\(d=177601976\\) at .*$srcfile1:$bp_location13\[\r\n\]+$bp_location13\[\t \]+void marker4.*" { ++ pass "run until breakpoint set at small function, optimized file" ++ } ++ -re "Breakpoint $decimal, marker4 \\(d=177601976\\) at .*$srcfile1:$bp_location14\[\r\n\]+$bp_location14\[\t \]+void marker4.*" { ++ # marker4() is defined at line 46 when compiled with -DPROTOTYPES ++ pass "run until breakpoint set at small function, optimized file (line bp_location14)" ++ } ++ -re ".*$gdb_prompt " { ++ fail "run until breakpoint set at small function, optimized file" ++ } ++ timeout { ++ fail "run until breakpoint set at small function, optimized file (timeout)" ++ } ++} ++ ++ ++# Reset the default arguments for VxWorks ++if [istarget "*-*-vxworks*"] { ++ set timeout 10 ++ verbose "Timeout is now $timeout seconds" 2 ++ send_gdb "set args main\n" ++ gdb_expect -re ".*$gdb_prompt $" {} ++} +Index: gdb-6.8.50.20081128/gdb/testsuite/gdb.pie/corefile.exp +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8.50.20081128/gdb/testsuite/gdb.pie/corefile.exp 2008-12-09 17:02:55.000000000 +0100 +@@ -0,0 +1,243 @@ ++# Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000 ++# Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++# Please email any bugs, comments, and/or additions to this file to: ++# bug-gdb@prep.ai.mit.edu ++ ++# This file was written by Fred Fish. (fnf@cygnus.com) ++ ++if $tracelevel then { ++ strace $tracelevel ++} ++ ++set prms_id 0 ++set bug_id 0 ++ ++# are we on a target board ++if ![isnative] then { ++ return ++} ++ ++set testfile "coremaker" ++set srcfile ${testfile}.c ++set binfile ${objdir}/${subdir}/${testfile} ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug "additional_flags=-fpie -pie"}] != "" } { ++ gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail." ++} ++ ++# Create and source the file that provides information about the compiler ++# used to compile the test case. ++if [get_compiler_info ${binfile}] { ++ return -1; ++} ++ ++# Create a core file named "corefile" rather than just "core", to ++# avoid problems with sys admin types that like to regularly prune all ++# files named "core" from the system. ++# ++# Arbitrarily try setting the core size limit to "unlimited" since ++# this does not hurt on systems where the command does not work and ++# allows us to generate a core on systems where it does. ++# ++# Some systems append "core" to the name of the program; others append ++# the name of the program to "core"; still others (like Linux, as of ++# May 2003) create cores named "core.PID". In the latter case, we ++# could have many core files lying around, and it may be difficult to ++# tell which one is ours, so let's run the program in a subdirectory. ++set found 0 ++set coredir "${objdir}/${subdir}/coredir.[getpid]" ++file mkdir $coredir ++catch "system \"(cd ${coredir}; ulimit -c unlimited; ${binfile}; true) >/dev/null 2>&1\"" ++# remote_exec host "${binfile}" ++foreach i "${coredir}/core ${coredir}/core.coremaker.c ${binfile}.core" { ++ if [remote_file build exists $i] { ++ remote_exec build "mv $i ${objdir}/${subdir}/corefile" ++ set found 1 ++ } ++} ++# Check for "core.PID". ++if { $found == 0 } { ++ set names [glob -nocomplain -directory $coredir core.*] ++ if {[llength $names] == 1} { ++ set corefile [file join $coredir [lindex $names 0]] ++ remote_exec build "mv $corefile ${objdir}/${subdir}/corefile" ++ set found 1 ++ } ++} ++if { $found == 0 } { ++ # The braindamaged HPUX shell quits after the ulimit -c above ++ # without executing ${binfile}. So we try again without the ++ # ulimit here if we didn't find a core file above. ++ # Oh, I should mention that any "braindamaged" non-Unix system has ++ # the same problem. I like the cd bit too, it's really neat'n stuff. ++ catch "system \"(cd ${objdir}/${subdir}; ${binfile}; true) >/dev/null 2>&1\"" ++ foreach i "${objdir}/${subdir}/core ${objdir}/${subdir}/core.coremaker.c ${binfile}.core" { ++ if [remote_file build exists $i] { ++ remote_exec build "mv $i ${objdir}/${subdir}/corefile" ++ set found 1 ++ } ++ } ++} ++ ++# Try to clean up after ourselves. ++remote_file build delete [file join $coredir coremmap.data] ++remote_exec build "rmdir $coredir" ++ ++if { $found == 0 } { ++ warning "can't generate a core file - core tests suppressed - check ulimit -c" ++ return 0 ++} ++ ++# ++# Test that we can simply startup with a "-core=corefile" command line arg ++# and recognize that the core file is a valid, usable core file. ++# To do this, we must shutdown the currently running gdb and restart ++# with the -core args. We can't use gdb_start because it looks for ++# the first gdb prompt, and the message we are looking for occurs ++# before the first prompt. Also, we can't include GDBFLAGS because ++# if it is empty, this confuses gdb with an empty argument that it ++# grumbles about (said grumbling currently being ignored in gdb_start). ++# **FIXME** ++# ++# Another problem is that on some systems (solaris for example), there ++# is apparently a limit on the length of a fully specified path to ++# the coremaker executable, at about 80 chars. For this case, consider ++# it a pass, but note that the program name is bad. ++ ++gdb_exit ++if $verbose>1 then { ++ send_user "Spawning $GDB -nw $GDBFLAGS -core=$objdir/$subdir/corefile\n" ++} ++ ++set oldtimeout $timeout ++set timeout [expr "$timeout + 60"] ++verbose "Timeout is now $timeout seconds" 2 ++eval "spawn $GDB -nw $GDBFLAGS -core=$objdir/$subdir/corefile" ++expect { ++ -re "Couldn't find .* registers in core file.*$gdb_prompt $" { ++ fail "args: -core=corefile (couldn't find regs)" ++ } ++ -re "Core was generated by .*coremaker.*\r\n\#0 .*\(\).*\r\n$gdb_prompt $" { ++ pass "args: -core=corefile" ++ } ++ -re "Core was generated by .*\r\n\#0 .*\(\).*\r\n$gdb_prompt $" { ++ pass "args: -core=corefile (with bad program name)" ++ } ++ -re ".*registers from core file: File in wrong format.* $" { ++ fail "args: -core=corefile (could not read registers from core file)" ++ } ++ -re ".*$gdb_prompt $" { fail "args: -core=corefile" } ++ timeout { fail "(timeout) starting with -core" } ++} ++ ++ ++# ++# Test that startup with both an executable file and -core argument. ++# See previous comments above, they are still applicable. ++# ++ ++close; ++ ++if $verbose>1 then { ++ send_user "Spawning $GDB -nw $GDBFLAGS $binfile -core=$objdir/$subdir/corefile\n" ++} ++ ++ ++eval "spawn $GDB -nw $GDBFLAGS $binfile -core=$objdir/$subdir/corefile"; ++expect { ++ -re "Core was generated by .*coremaker.*\r\n\#0 .*\(\).*\r\n$gdb_prompt $" { ++ pass "args: execfile -core=corefile" ++ } ++ -re "Core was generated by .*\r\n\#0 .*\(\).*\r\n$gdb_prompt $" { ++ pass "args: execfile -core=corefile (with bad program name)" ++ } ++ -re ".*registers from core file: File in wrong format.* $" { ++ fail "args: execfile -core=corefile (could not read registers from core file)" ++ } ++ -re ".*$gdb_prompt $" { fail "args: execfile -core=corefile" } ++ timeout { fail "(timeout) starting with -core" } ++} ++set timeout $oldtimeout ++verbose "Timeout is now $timeout seconds" 2 ++ ++close; ++ ++# Now restart normally. ++ ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++# Test basic corefile recognition via core-file command. ++ ++send_gdb "core-file $objdir/$subdir/corefile\n" ++gdb_expect { ++ -re ".* program is being debugged already.*y or n. $" { ++ # gdb_load may connect us to a gdbserver. ++ send_gdb "y\n" ++ exp_continue; ++ } ++ -re "Core was generated by .*coremaker.*\r\n\#0 .*\(\).*\r\n$gdb_prompt $" { ++ pass "core-file command" ++ } ++ -re "Core was generated by .*\r\n\#0 .*\(\).*\r\n$gdb_prompt $" { ++ pass "core-file command (with bad program name)" ++ } ++ -re ".*registers from core file: File in wrong format.* $" { ++ fail "core-file command (could not read registers from core file)" ++ } ++ -re ".*$gdb_prompt $" { fail "core-file command" } ++ timeout { fail "(timeout) core-file command" } ++} ++ ++# Test correct mapping of corefile sections by printing some variables. ++ ++gdb_test "print coremaker_data" "\\\$$decimal = 202" ++gdb_test "print coremaker_bss" "\\\$$decimal = 10" ++gdb_test "print coremaker_ro" "\\\$$decimal = 201" ++ ++gdb_test "print func2::coremaker_local" "\\\$$decimal = \\{0, 1, 2, 3, 4\\}" ++ ++# Somehow we better test the ability to read the registers out of the core ++# file correctly. I don't think the other tests do this. ++ ++gdb_test "bt" "abort.*func2.*func1.*main.*" "backtrace in corefile.exp" ++gdb_test "up" "#\[0-9\]* *\[0-9xa-fH'\]* in .* \\(.*\\).*" "up in corefile.exp" ++ ++# Test ability to read mmap'd data ++ ++gdb_test "x/8bd buf1" ".*:.*0.*1.*2.*3.*4.*5.*6.*7" "accessing original mmap data in core file" ++setup_xfail "*-*-sunos*" "*-*-ultrix*" "*-*-aix*" ++set test "accessing mmapped data in core file" ++gdb_test_multiple "x/8bd buf2" "$test" { ++ -re ".*:.*0.*1.*2.*3.*4.*5.*6.*7.*$gdb_prompt $" { ++ pass "$test" ++ } ++ -re "0x\[f\]*:.*Cannot access memory at address 0x\[f\]*.*$gdb_prompt $" { ++ fail "$test (mapping failed at runtime)" ++ } ++ -re "0x.*:.*Cannot access memory at address 0x.*$gdb_prompt $" { ++ fail "$test (mapping address not found in core file)" ++ } ++} ++ ++# test reinit_frame_cache ++ ++gdb_load ${binfile} ++gdb_test "up" "#\[0-9\]* *\[0-9xa-fH'\]* in .* \\(\\).*" "up in corefile.exp (reinit)" ++ ++gdb_test "core" "No core file now." +Index: gdb-6.8.50.20081128/gdb/testsuite/gdb.pie/Makefile.in +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8.50.20081128/gdb/testsuite/gdb.pie/Makefile.in 2008-12-09 17:02:55.000000000 +0100 +@@ -0,0 +1,19 @@ ++VPATH = @srcdir@ ++srcdir = @srcdir@ ++ ++EXECUTABLES = ++MISCELLANEOUS = arch.inc ++ ++all info install-info dvi install uninstall installcheck check: ++ @echo "Nothing to be done for $@..." ++ ++clean mostlyclean: ++ -rm -f *~ *.o a.out *.x *.ci *.tmp ++ -rm -f core core.coremaker coremaker.core corefile $(EXECUTABLES) ++ -rm -f $(MISCELLANEOUS) ++ ++distclean maintainer-clean realclean: clean ++ -rm -f *~ core ++ -rm -f Makefile config.status config.log ++ -rm -f *-init.exp ++ -rm -fr *.log summary detail *.plog *.sum *.psum site.* diff --git a/gdb-6.3-test-self-20050110.patch b/gdb-6.3-test-self-20050110.patch new file mode 100644 index 0000000..a3ada08 --- /dev/null +++ b/gdb-6.3-test-self-20050110.patch @@ -0,0 +1,101 @@ +2004-02-23 Elena Zannoni + + * gdb.gdb/selftest.exp: Make sure that the debug directory is + set up properly. + * gdb.gdb/complaints.exp: Ditto. + * gdb.gdb/xfullpath.exp: Ditto. + * gdb.gdb/observer.exp: Ditto. + +Index: gdb-6.8.50.20090226/gdb/testsuite/gdb.gdb/complaints.exp +=================================================================== +--- gdb-6.8.50.20090226.orig/gdb/testsuite/gdb.gdb/complaints.exp 2009-01-03 06:58:04.000000000 +0100 ++++ gdb-6.8.50.20090226/gdb/testsuite/gdb.gdb/complaints.exp 2009-02-26 22:10:48.000000000 +0100 +@@ -302,13 +302,13 @@ proc find_gdb { arg } { + set GDB_FULLPATH [find_gdb $GDB] + + # Remove any old copy lying around. +-remote_file host delete x$tool ++#remote_file host delete x$tool + + gdb_start + +-set file [remote_download host $GDB_FULLPATH x$tool] ++#set file [remote_download host $GDB_FULLPATH x$tool] + +-set setup_result [setup_test $file ] ++set setup_result [setup_test $GDB_FULLPATH ] + if {$setup_result <0} then { + return -1 + } +@@ -319,4 +319,4 @@ test_short_complaints + test_empty_complaints + + gdb_exit; +-catch "remote_file host delete $file"; ++#catch "remote_file host delete $file"; +Index: gdb-6.8.50.20090226/gdb/testsuite/gdb.gdb/observer.exp +=================================================================== +--- gdb-6.8.50.20090226.orig/gdb/testsuite/gdb.gdb/observer.exp 2009-02-17 20:52:27.000000000 +0100 ++++ gdb-6.8.50.20090226/gdb/testsuite/gdb.gdb/observer.exp 2009-02-26 22:11:40.000000000 +0100 +@@ -258,13 +258,13 @@ proc find_gdb { arg } { + set GDB_FULLPATH [find_gdb $GDB] + + # Remove any old copy lying around. +-remote_file host delete x$tool ++#remote_file host delete x$tool + + gdb_start +-set file [remote_download host $GDB_FULLPATH x$tool] +-set result [test_observer $file]; ++#set file [remote_download host $GDB_FULLPATH x$tool] ++set result [test_observer $GDB_FULLPATH]; + gdb_exit; +-catch "remote_file host delete $file"; ++#catch "remote_file host delete $file"; + + if {$result <0} then { + warning "Couldn't test self" +Index: gdb-6.8.50.20090226/gdb/testsuite/gdb.gdb/selftest.exp +=================================================================== +--- gdb-6.8.50.20090226.orig/gdb/testsuite/gdb.gdb/selftest.exp 2009-02-26 22:09:59.000000000 +0100 ++++ gdb-6.8.50.20090226/gdb/testsuite/gdb.gdb/selftest.exp 2009-02-26 22:10:48.000000000 +0100 +@@ -551,13 +551,13 @@ proc find_gdb { arg } { + set GDB_FULLPATH [find_gdb $GDB] + + # Remove any old copy lying around. +-remote_file host delete x$tool ++#remote_file host delete x$tool + + gdb_start +-set file [remote_download host $GDB_FULLPATH x$tool] +-set result [test_with_self $file]; ++#set file [remote_download host $GDB_FULLPATH x$tool] ++set result [test_with_self $GDB_FULLPATH]; + gdb_exit; +-catch "remote_file host delete $file"; ++#catch "remote_file host delete $file"; + + if {$result <0} then { + warning "Couldn't test self" +Index: gdb-6.8.50.20090226/gdb/testsuite/gdb.gdb/xfullpath.exp +=================================================================== +--- gdb-6.8.50.20090226.orig/gdb/testsuite/gdb.gdb/xfullpath.exp 2009-01-03 06:58:04.000000000 +0100 ++++ gdb-6.8.50.20090226/gdb/testsuite/gdb.gdb/xfullpath.exp 2009-02-26 22:10:48.000000000 +0100 +@@ -179,13 +179,13 @@ proc find_gdb { arg } { + set GDB_FULLPATH [find_gdb $GDB] + + # Remove any old copy lying around. +-remote_file host delete x$tool ++#remote_file host delete x$tool + + gdb_start +-set file [remote_download host $GDB_FULLPATH x$tool] +-set result [test_with_self $file]; ++#set file [remote_download host $GDB_FULLPATH x$tool] ++set result [test_with_self $GDB_FULLPATH]; + gdb_exit; +-catch "remote_file host delete $file"; ++#catch "remote_file host delete $file"; + + if {$result <0} then { + warning "Couldn't test self" diff --git a/gdb-6.3-test-sepcrc-20050402.patch b/gdb-6.3-test-sepcrc-20050402.patch new file mode 100644 index 0000000..65e086f --- /dev/null +++ b/gdb-6.3-test-sepcrc-20050402.patch @@ -0,0 +1,55 @@ +Index: gdb-6.8/gdb/testsuite/gdb.base/sepdebug.exp +=================================================================== +--- gdb-6.8.orig/gdb/testsuite/gdb.base/sepdebug.exp 2008-02-26 09:14:11.000000000 +0100 ++++ gdb-6.8/gdb/testsuite/gdb.base/sepdebug.exp 2008-07-14 10:26:19.000000000 +0200 +@@ -981,3 +981,40 @@ if ![string compare $build_id_debug_file + # Spare debug files may confuse testsuite runs in the future. + remote_exec build "rm -f ${objdir}/${subdir}/${build_id_debug_filename}" + } ++ ++ ++# Compile up a second, different, object file. Copy its debug info ++# over the top of the new debug info. Note that somewhere in the ++# above the "set debug-file-directory" variable is set to ++# ${objdir}/${subdir} so need to move things there. ++ ++set existing_binfile $binfile ++set testfile "sepdebug2" ++set srcfile ${testfile}.c ++set binfile ${objdir}/${subdir}/${testfile} ++set corrupt_debug_file [separate_debug_filename $binfile] ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug additional_flags=-w}] != "" } { ++ return -1 ++} ++if [gdb_gnu_strip_debug $binfile] { ++ # check that you have a recent version of strip and objcopy installed ++ unsupported "cannot produce separate debug info files" ++ return -1 ++} ++remote_exec build "cp $corrupt_debug_file ${existing_binfile}.debug" ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++set test "A corrupt debug file gets a warning" ++gdb_test_multiple "file $existing_binfile" "$test" { ++ -re "warning:.*mismatch.*" { ++ pass "$test" ++ } ++ -re ".y or n. " { ++ send_gdb "y\n" ++ exp_continue ++ } ++} +Index: gdb-6.8/gdb/testsuite/gdb.base/sepdebug2.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8/gdb/testsuite/gdb.base/sepdebug2.c 2008-07-14 10:26:19.000000000 +0200 +@@ -0,0 +1,5 @@ ++int ++main (int argc, char *argv[], char *envp[]) ++{ ++ return 0; ++} diff --git a/gdb-6.3-threaded-watchpoints2-20050225.patch b/gdb-6.3-threaded-watchpoints2-20050225.patch new file mode 100644 index 0000000..2d7965c --- /dev/null +++ b/gdb-6.3-threaded-watchpoints2-20050225.patch @@ -0,0 +1,250 @@ +2005-02-28 Jeff Johnston + + * config/i386/nm-linux.h: Change dr register routines to + accept a ptid_t first argument. Change all calling macros + to default the inferior_ptid for the first argument. + (i386_linux_insert_watchpoint): New prototype. + (i386_linux_remove_watchpoint, i386_linux_insert_hw_breakpoint): Ditto. + (i386_linux_remove_hw_breakpoint): Ditto. + (target_insert_watchpoint, target_remove_watchpoint): Undef and + override. + (target_insert_hw_breakpoint, target_remove_hw_breakpoint): Ditto. + * config/i386/nm-linux64.h: Ditto except add amd64 versions of + the watchpoint/hw-breakpoint insert/remove routines. + * i386-nat.c: Include "inferior.h" to define inferior_ptid. + * i386-linux-nat.c: Change all dr get/set routines to accept + ptid_t as first argument and to use this argument to determine + the tid for PTRACE. + (i386_linux_set_debug_regs_for_thread): New function. + (i386_linux_sync_debug_registers_callback): Ditto. + (i386_linux_sync_debug_registers_across_threads): Ditto. + (i386_linux_insert_watchpoint, i386_linux_remove_watchpoint): Ditto. + (i386_linux_hw_breakpoint, i386_linux_remove_hw_breakpoint): Ditto. + (i386_linux_new_thread): Ditto. + (_initialize_i386_linux_nat): Ditto. + * amd64-linux-nat.c: Change all dr get/set routines to accept + ptid_t as first argument and to use this argument to determine + the tid for PTRACE. + (amd64_linux_set_debug_regs_for_thread): New function. + (amd64_linux_sync_debug_registers_callback): Ditto. + (amd64_linux_sync_debug_registers_across_threads): Ditto. + (amd64_linux_insert_watchpoint, amd64_linux_remove_watchpoint): Ditto. + (amd64_linux_hw_breakpoint, amd64_linux_remove_hw_breakpoint): Ditto. + (amd64_linux_new_thread): Ditto. + (_initialize_amd64_linux_nat): Register linux new thread observer. + * testsuite/gdb.threads/watchthreads2.c: New test case. + * testsuite/gdb.threads/watchthreads2.exp: Ditto. + +[ With recent upstream GDB (6.8) reduced only to the testcase. ] + +FIXME: The testcase does not expects multiple watchpoints hits per one stop. + +Index: gdb-6.5/gdb/testsuite/gdb.threads/watchthreads2.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.5/gdb/testsuite/gdb.threads/watchthreads2.c 2006-07-12 01:54:29.000000000 -0300 +@@ -0,0 +1,66 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2002, 2003, 2004, 2005 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place - Suite 330, ++ Boston, MA 02111-1307, USA. ++ ++ This file is copied from schedlock.c. */ ++ ++#include ++#include ++#include ++#include ++ ++void *thread_function(void *arg); /* Pointer to function executed by each thread */ ++ ++#define NUM 5 ++ ++unsigned int args[NUM+1]; ++ ++int main() { ++ int res; ++ pthread_t threads[NUM]; ++ void *thread_result; ++ long i; ++ ++ for (i = 0; i < NUM; i++) ++ { ++ args[i] = 1; /* Init value. */ ++ res = pthread_create(&threads[i], ++ NULL, ++ thread_function, ++ (void *) i); ++ } ++ ++ args[i] = 1; ++ thread_function ((void *) i); ++ ++ exit(EXIT_SUCCESS); ++} ++ ++void *thread_function(void *arg) { ++ int my_number = (long) arg; ++ int *myp = (int *) &args[my_number]; ++ ++ /* Don't run forever. Run just short of it :) */ ++ while (*myp > 0) ++ { ++ (*myp) ++; usleep (1); /* Loop increment. */ ++ } ++ ++ pthread_exit(NULL); ++} ++ +Index: gdb-6.5/gdb/testsuite/gdb.threads/watchthreads2.exp +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.5/gdb/testsuite/gdb.threads/watchthreads2.exp 2006-07-12 01:54:29.000000000 -0300 +@@ -0,0 +1,133 @@ ++# This testcase is part of GDB, the GNU debugger. ++ ++# Copyright 2005 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++# Check that GDB can support multiple watchpoints across threads. ++ ++if $tracelevel { ++ strace $tracelevel ++} ++ ++set prms_id 0 ++set bug_id 0 ++ ++# This test verifies that a watchpoint is detected in the proper thread ++# so the test is only meaningful on a system with hardware watchpoints. ++if [target_info exists gdb,no_hardware_watchpoints] { ++ return 0; ++} ++ ++set testfile "watchthreads2" ++set srcfile ${testfile}.c ++set binfile ${objdir}/${subdir}/${testfile} ++if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable [list debug "incdir=${objdir}"]] != "" } { ++ return -1 ++} ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++gdb_test "set can-use-hw-watchpoints 1" "" "" ++ ++# ++# Run to `main' where we begin our tests. ++# ++ ++if ![runto_main] then { ++ gdb_suppress_tests ++} ++ ++set args_2 0 ++set args_3 0 ++ ++gdb_breakpoint "thread_function" ++gdb_continue_to_breakpoint "thread_function" ++gdb_test "disable 2" "" ++ ++gdb_test_multiple "p args\[2\]" "get initial args2" { ++ -re "\\\$\[0-9\]* = (.*)$gdb_prompt $" { ++ set init_args_2 $expect_out(1,string) ++ pass "get initial args2" ++ } ++} ++ ++gdb_test_multiple "p args\[3\]" "get initial args3" { ++ -re "\\\$\[0-9\]* = (.*)$gdb_prompt $" { ++ set init_args_3 $expect_out(1,string) ++ pass "get initial args3" ++ } ++} ++ ++set args_2 $init_args_2 ++set args_3 $init_args_3 ++ ++# Watch values that will be modified by distinct threads. ++gdb_test "watch args\[2\]" "Hardware watchpoint 3: args\\\[2\\\]" ++gdb_test "watch args\[3\]" "Hardware watchpoint 4: args\\\[3\\\]" ++ ++set init_line [expr [gdb_get_line_number "Init value"]+1] ++set inc_line [gdb_get_line_number "Loop increment"] ++ ++# Loop and continue to allow both watchpoints to be triggered. ++for {set i 0} {$i < 30} {incr i} { ++ set test_flag 0 ++ gdb_test_multiple "continue" "threaded watch loop" { ++ -re "Hardware watchpoint 3: args\\\[2\\\].*Old value = 0.*New value = 1.*main \\\(\\\) at .*watchthreads2.c:$init_line.*$gdb_prompt $" ++ { set args_2 1; set test_flag 1 } ++ -re "Hardware watchpoint 4: args\\\[3\\\].*Old value = 0.*New value = 1.*main \\\(\\\) at .*watchthreads2.c:$init_line.*$gdb_prompt $" ++ { set args_3 1; set test_flag 1 } ++ -re "Hardware watchpoint 3: args\\\[2\\\].*Old value = $args_2.*New value = [expr $args_2+1].*in thread_function \\\(arg=0x2\\\) at .*watchthreads2.c:$inc_line.*$gdb_prompt $" ++ { set args_2 [expr $args_2+1]; set test_flag 1 } ++ -re "Hardware watchpoint 4: args\\\[3\\\].*Old value = $args_3.*New value = [expr $args_3+1].*in thread_function \\\(arg=0x3\\\) at .*watchthreads2.c:$inc_line.*$gdb_prompt $" ++ { set args_3 [expr $args_3+1]; set test_flag 1 } ++ } ++ # If we fail above, don't bother continuing loop ++ if { $test_flag == 0 } { ++ set i 30; ++ } ++} ++ ++# Print success message if loop succeeded. ++if { $test_flag == 1 } { ++ pass "threaded watch loop" ++} ++ ++# Verify that we hit first watchpoint in child thread. ++set message "watchpoint on args\[2\] hit in thread" ++if { $args_2 > 1 } { ++ pass $message ++} else { ++ fail $message ++} ++ ++# Verify that we hit second watchpoint in child thread. ++set message "watchpoint on args\[3\] hit in thread" ++if { $args_3 > 1 } { ++ pass $message ++} else { ++ fail $message ++} ++ ++# Verify that all watchpoint hits are accounted for. ++set message "combination of threaded watchpoints = 30 + initial values" ++if { [expr $args_2+$args_3] == [expr [expr 30+$init_args_2]+$init_args_3] } { ++ pass $message ++} else { ++ fail $message ++} diff --git a/gdb-6.3-watchpoint-cond-gone-test.patch b/gdb-6.3-watchpoint-cond-gone-test.patch new file mode 100644 index 0000000..cd8a237 --- /dev/null +++ b/gdb-6.3-watchpoint-cond-gone-test.patch @@ -0,0 +1,128 @@ +--- /dev/null 2008-04-03 00:39:30.714021604 +0200 ++++ gdb-6.3/gdb/testsuite/gdb.base/watchpoint-cond-gone-stripped.c 2008-04-05 20:26:29.000000000 +0200 +@@ -0,0 +1,23 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2008 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ ++ ++void ++jumper (void (*jumpto) (void)) ++{ ++ (*jumpto) (); ++} +--- /dev/null 2008-04-03 00:39:30.714021604 +0200 ++++ gdb-6.3/gdb/testsuite/gdb.base/watchpoint-cond-gone.c 2008-04-05 20:26:48.000000000 +0200 +@@ -0,0 +1,37 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2008 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ ++ ++extern void jumper (void (*jumpto) (void)); ++ ++void ++func () ++{ ++ int a, b, c; ++ ++ a = b = c = 5; ++ a = b = c = 10; /* watchpoint-here */ ++ c = a + b; ++} ++ ++int ++main () ++{ ++ jumper (func); ++ ++ return 0; ++} +--- /dev/null 2008-04-03 00:39:30.714021604 +0200 ++++ gdb-6.3/gdb/testsuite/gdb.base/watchpoint-cond-gone.exp 2008-04-05 20:33:19.000000000 +0200 +@@ -0,0 +1,59 @@ ++# Copyright 2008 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++if $tracelevel then { ++ strace $tracelevel ++} ++ ++set testfile "watchpoint-cond-gone" ++set srcfile ${testfile}.c ++set srcfilestripped ${testfile}-stripped.c ++set objfilestripped ${objdir}/${subdir}/${testfile}-stripped.o ++set binfile ${objdir}/${subdir}/${testfile} ++ ++# We need to generate a function without DWARF to crash older GDB. ++# Stepping into a dynamic function trampoline or stepping out of MAIN may work ++# but it is not a reliable FAIL case. ++ ++if { [gdb_compile "${srcdir}/${subdir}/${srcfilestripped}" "${objfilestripped}" object {}] != "" } { ++ gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail." ++} ++ ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile} ${objfilestripped}" "${binfile}" executable {debug}] != "" } { ++ gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail." ++} ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++# Problem does not occur otherwise. ++gdb_test "set can-use-hw-watchpoints 0" ++ ++runto_main ++gdb_breakpoint [gdb_get_line_number "watchpoint-here"] ++gdb_continue_to_breakpoint "Place to set the watchpoint" ++ ++# The condition `c == 30' is the tested culprit. ++gdb_test "watch c if c == 30" "" "Place the watchpoint" ++ ++# No functionality, just to check the state. ++gdb_test "backtrace" ++ ++gdb_test "finish" \ ++ "Watchpoint .* deleted because the program has left the block in.*which its expression is valid..*in (jumper|func).*" \ ++ "Catch the no longer valid watchpoint" diff --git a/gdb-6.5-BEA-testsuite.patch b/gdb-6.5-BEA-testsuite.patch new file mode 100644 index 0000000..76d7566 --- /dev/null +++ b/gdb-6.5-BEA-testsuite.patch @@ -0,0 +1,938 @@ +Index: ./gdb/testsuite/gdb.threads/threadcrash.c +=================================================================== +RCS file: gdb/testsuite/gdb.threads/threadcrash.c +diff -N gdb/testsuite/gdb.threads/threadcrash.c +--- /dev/null 1 Jan 1970 00:00:00 -0000 ++++ ./gdb/testsuite/gdb.threads/threadcrash.c 31 Oct 2006 17:54:38 -0000 +@@ -0,0 +1,301 @@ ++/* ++ * The point of this program is to crash in a multi-threaded app. ++ * There are seven threads, doing the following things: ++ * * Spinning ++ * * Spinning inside a signal handler ++ * * Spinning inside a signal handler executing on the altstack ++ * * In a syscall ++ * * In a syscall inside a signal handler ++ * * In a syscall inside a signal handler executing on the altstack ++ * * Finally, the main thread crashes in main, with no frills. ++ * ++ * These are the things threads in JRockit tend to be doing. If gdb ++ * can handle those things, both in core files and during live ++ * debugging, that will help (at least) JRockit development. ++ * ++ * Let the program create a core file, then load the core file into ++ * gdb. Inside gdb, you should be able to do something like this: ++ * ++ * (gdb) t a a bt ++ * ++ * Thread 7 (process 4352): ++ * #0 0x001ba7dc in __nanosleep_nocancel () from /lib/tls/libc.so.6 ++ * #1 0x001ba5ff in sleep () from /lib/tls/libc.so.6 ++ * #2 0x080488a2 in makeSyscall (ignored=0x0) at threadcrash.c:118 ++ * #3 0x006aadec in start_thread () from /lib/tls/libpthread.so.0 ++ * #4 0x001ed19a in clone () from /lib/tls/libc.so.6 ++ * ++ * Thread 6 (process 4353): ++ * #0 0x001ba7dc in __nanosleep_nocancel () from /lib/tls/libc.so.6 ++ * #1 0x001ba5ff in sleep () from /lib/tls/libc.so.6 ++ * #2 0x0804898f in syscallingSighandler (signo=10, info=0xb6be76f0, context=0xb6be7770) ++ * at threadcrash.c:168 ++ * #3 ++ * #4 0x006adf5e in pthread_kill () from /lib/tls/libpthread.so.0 ++ * #5 0x08048a51 in makeSyscallFromSighandler (ignored=0x0) at threadcrash.c:204 ++ * #6 0x006aadec in start_thread () from /lib/tls/libpthread.so.0 ++ * #7 0x001ed19a in clone () from /lib/tls/libc.so.6 ++ * ++ * Thread 5 (process 4354): ++ * #0 0x001ba7dc in __nanosleep_nocancel () from /lib/tls/libc.so.6 ++ * #1 0x001ba5ff in sleep () from /lib/tls/libc.so.6 ++ * #2 0x08048936 in syscallingAltSighandler (signo=3, info=0x959cd70, context=0x959cdf0) ++ * at threadcrash.c:144 ++ * #3 ++ * #4 0x006adf5e in pthread_kill () from /lib/tls/libpthread.so.0 ++ * #5 0x080489e2 in makeSyscallFromAltSighandler (ignored=0x0) at threadcrash.c:190 ++ * #6 0x006aadec in start_thread () from /lib/tls/libpthread.so.0 ++ * #7 0x001ed19a in clone () from /lib/tls/libc.so.6 ++ * ++ * Thread 4 (process 4355): ++ * #0 spin (ignored=0x0) at threadcrash.c:242 ++ * #1 0x006aadec in start_thread () from /lib/tls/libpthread.so.0 ++ * #2 0x001ed19a in clone () from /lib/tls/libc.so.6 ++ * ++ * Thread 3 (process 4356): ++ * #0 spinningSighandler (signo=12, info=0xb4de46f0, context=0xb4de4770) at threadcrash.c:180 ++ * #1 ++ * #2 0x006adf5e in pthread_kill () from /lib/tls/libpthread.so.0 ++ * #3 0x08048b2f in spinFromSighandler (ignored=0x0) at threadcrash.c:232 ++ * #4 0x006aadec in start_thread () from /lib/tls/libpthread.so.0 ++ * #5 0x001ed19a in clone () from /lib/tls/libc.so.6 ++ * ++ * Thread 2 (process 4357): ++ * #0 spinningAltSighandler (signo=14, info=0x959ee50, context=0x959eed0) at threadcrash.c:156 ++ * #1 ++ * #2 0x006adf5e in pthread_kill () from /lib/tls/libpthread.so.0 ++ * #3 0x08048ac0 in spinFromAltSighandler (ignored=0x0) at threadcrash.c:218 ++ * #4 0x006aadec in start_thread () from /lib/tls/libpthread.so.0 ++ * #5 0x001ed19a in clone () from /lib/tls/libc.so.6 ++ * ++ * Thread 1 (process 4351): ++ * #0 0x08048cf3 in main (argc=1, argv=0xbfff9d74) at threadcrash.c:273 ++ * (gdb) ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define SIGSYSCALL_ALT SIGQUIT ++#define SIGSYSCALL SIGUSR1 ++#define SIGSPIN_ALT SIGALRM ++#define SIGSPIN SIGUSR2 ++ ++typedef void (*sigaction_t)(int, siginfo_t *, void *); ++ ++static void installHandler(int signo, sigaction_t handler, int onAltstack) { ++ struct sigaction action; ++ sigset_t sigset; ++ int result; ++ stack_t altstack; ++ stack_t oldaltstack; ++ ++ memset(&action, 0, sizeof(action)); ++ memset(&altstack, 0, sizeof(altstack)); ++ memset(&oldaltstack, 0, sizeof(oldaltstack)); ++ ++ if (onAltstack) { ++ altstack.ss_sp = malloc(SIGSTKSZ); ++ assert(altstack.ss_sp != NULL); ++ altstack.ss_size = SIGSTKSZ; ++ altstack.ss_flags = 0; ++ result = sigaltstack(&altstack, &oldaltstack); ++ assert(result == 0); ++ assert(oldaltstack.ss_flags == SS_DISABLE); ++ } ++ ++ sigemptyset(&sigset); ++ ++ action.sa_handler = NULL; ++ action.sa_sigaction = handler; ++ action.sa_mask = sigset; ++ action.sa_flags = SA_SIGINFO; ++ if (onAltstack) { ++ action.sa_flags |= SA_ONSTACK; ++ } ++ ++ result = sigaction(signo, &action, NULL); ++ assert(result == 0); ++} ++ ++static void installNormalHandler(int signo, sigaction_t handler) { ++ installHandler(signo, handler, 0); ++} ++ ++static void installAlthandler(int signo, sigaction_t handler) { ++ installHandler(signo, handler, 1); ++} ++ ++static void *makeSyscall(void *ignored) { ++ (void)ignored; ++ ++ sleep(42); ++ ++ fprintf(stderr, "%s: returning\n", __FUNCTION__); ++ return NULL; ++} ++ ++/* Return true if we're currently executing on the altstack */ ++static int onAltstack(void) { ++ stack_t stack; ++ int result; ++ ++ result = sigaltstack(NULL, &stack); ++ assert(result == 0); ++ ++ return stack.ss_flags & SS_ONSTACK; ++} ++ ++static void syscallingAltSighandler(int signo, siginfo_t *info, void *context) { ++ (void)signo; ++ (void)info; ++ (void)context; ++ ++ if (!onAltstack()) { ++ printf("%s() not running on altstack!\n", __FUNCTION__); ++ } ++ ++ sleep(42); ++} ++ ++static void spinningAltSighandler(int signo, siginfo_t *info, void *context) { ++ (void)signo; ++ (void)info; ++ (void)context; ++ ++ if (!onAltstack()) { ++ printf("%s() not running on altstack!\n", __FUNCTION__); ++ } ++ ++ while (1); ++} ++ ++static void syscallingSighandler(int signo, siginfo_t *info, void *context) { ++ (void)signo; ++ (void)info; ++ (void)context; ++ ++ if (onAltstack()) { ++ printf("%s() running on altstack!\n", __FUNCTION__); ++ } ++ ++ sleep(42); ++} ++ ++static void spinningSighandler(int signo, siginfo_t *info, void *context) { ++ (void)signo; ++ (void)info; ++ (void)context; ++ ++ if (onAltstack()) { ++ printf("%s() running on altstack!\n", __FUNCTION__); ++ } ++ ++ while (1); ++} ++ ++static void *makeSyscallFromAltSighandler(void *ignored) { ++ (void)ignored; ++ ++ int result; ++ ++ installAlthandler(SIGSYSCALL_ALT, syscallingAltSighandler); ++ ++ result = pthread_kill(pthread_self(), SIGSYSCALL_ALT); ++ assert(result == 0); ++ ++ fprintf(stderr, "%s: returning\n", __FUNCTION__); ++ return NULL; ++} ++ ++static void *makeSyscallFromSighandler(void *ignored) { ++ (void)ignored; ++ ++ int result; ++ ++ installNormalHandler(SIGSYSCALL, syscallingSighandler); ++ ++ result = pthread_kill(pthread_self(), SIGSYSCALL); ++ assert(result == 0); ++ ++ fprintf(stderr, "%s: returning\n", __FUNCTION__); ++ return NULL; ++} ++ ++static void *spinFromAltSighandler(void *ignored) { ++ (void)ignored; ++ ++ int result; ++ ++ installAlthandler(SIGSPIN_ALT, spinningAltSighandler); ++ ++ result = pthread_kill(pthread_self(), SIGSPIN_ALT); ++ assert(result == 0); ++ ++ fprintf(stderr, "%s: returning\n", __FUNCTION__); ++ return NULL; ++} ++ ++static void *spinFromSighandler(void *ignored) { ++ (void)ignored; ++ ++ int result; ++ ++ installNormalHandler(SIGSPIN, spinningSighandler); ++ ++ result = pthread_kill(pthread_self(), SIGSPIN); ++ assert(result == 0); ++ ++ fprintf(stderr, "%s: returning\n", __FUNCTION__); ++ return NULL; ++} ++ ++static void *spin(void *ignored) { ++ (void)ignored; ++ ++ while (1); ++ ++ fprintf(stderr, "%s: returning\n", __FUNCTION__); ++ return NULL; ++} ++ ++int main(int argc, char *argv[]) { ++ int result; ++ pthread_t thread; ++ volatile int bad; ++ ++ result = pthread_create(&thread, NULL, makeSyscall, NULL); ++ assert(result == 0); ++ result = pthread_create(&thread, NULL, makeSyscallFromSighandler, NULL); ++ assert(result == 0); ++ result = pthread_create(&thread, NULL, makeSyscallFromAltSighandler, NULL); ++ assert(result == 0); ++ result = pthread_create(&thread, NULL, spin, NULL); ++ assert(result == 0); ++ result = pthread_create(&thread, NULL, spinFromSighandler, NULL); ++ assert(result == 0); ++ result = pthread_create(&thread, NULL, spinFromAltSighandler, NULL); ++ assert(result == 0); ++ ++ // Give threads some time to get going ++ sleep(3); ++ ++ // Crash ++ bad = *(int*)7; ++ ++ /* Workaround: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=29628 ++ Simulate use to ensure `DW_AT_location' for them: ++ readelf -a --debug threadcrash|grep -A5 -w argc ++ --> DW_AT_location : 2 byte block: 71 0 (DW_OP_breg1: 0) ++ This case verified on: gcc-4.1.1-30.i386 ++ Keep it late to ensure persistency in the registers. */ ++ bad = (int) argc; ++ bad = (unsigned long) argv; ++ ++ return 0; ++} +Index: ./gdb/testsuite/gdb.threads/threadcrash.exp +=================================================================== +RCS file: gdb/testsuite/gdb.threads/threadcrash.exp +diff -N gdb/testsuite/gdb.threads/threadcrash.exp +--- /dev/null 1 Jan 1970 00:00:00 -0000 ++++ ./gdb/testsuite/gdb.threads/threadcrash.exp 31 Oct 2006 17:54:38 -0000 +@@ -0,0 +1,37 @@ ++# threadcrash.exp - The point of this program is to crash in a multi-threaded app. ++ ++ ++set testfile threadcrash ++set srcfile ${testfile}.c ++set shellfile ${srcdir}/${subdir}/${testfile}.sh ++set binfile ${objdir}/${subdir}/${testfile} ++ ++set GDB_abs ${GDB} ++if [regexp "^\[^/\]" ${GDB_abs}] { ++ set GDB_abs $env(PWD)/${GDB_abs} ++} ++ ++if [istarget "*-*-linux"] then { ++ set target_cflags "-D_MIT_POSIX_THREADS" ++} else { ++ set target_cflags "" ++} ++ ++if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { ++ return -1 ++} ++ ++# ${shellfile} argument must not contain any directories. ++set fd [open "|bash ${shellfile} ${binfile} $GDB -nw $GDBFLAGS" r] ++while { [gets $fd line] >= 0 } { ++ if [regexp " PASS: (.*)$" $line trash message] { ++ pass $message ++ } elseif [regexp " FAIL: (.*)$" $line trash message] { ++ fail $message ++ } ++} ++catch { ++ close $fd ++} ++ ++return 0 +Index: ./gdb/testsuite/gdb.threads/threadcrash.sh +=================================================================== +RCS file: gdb/testsuite/gdb.threads/threadcrash.sh +diff -N gdb/testsuite/gdb.threads/threadcrash.sh +--- /dev/null 1 Jan 1970 00:00:00 -0000 ++++ ./gdb/testsuite/gdb.threads/threadcrash.sh 31 Oct 2006 17:54:38 -0000 +@@ -0,0 +1,324 @@ ++#! /bin/bash ++ ++# NOTE: threadcrash.c *must* be built with debugging symbols ++# ++# The point of this shell script is to crash treadcrash.c, load the ++# resulting core file into gdb and verify that gdb can extract enough ++# information from the core file. ++# ++# The return code from this script is the number of failed tests. ++ ++LOG=gdbresult.log ++ ++if [ $# = 0 ] ; then ++ echo >&2 Syntax: $0 \ [\ \] ++ exit 1 ++fi ++RUNME="$1" ++shift ++GDB="${*:-gdb}" ++ ++ ++pf_prefix="" ++function pf_prefix() { ++ pf_prefix="$*" ++} ++ ++set_test="" ++function set_test() { ++ if [ -n "$set_test" ] ; then ++ echo >&2 "DEJAGNU-BASH ERROR: set_test already set" ++ exit 1 ++ fi ++ set_test="$*" ++ if [ -n "$pf_prefix" ] ; then ++ set_test="$pf_prefix: $set_test" ++ fi ++} ++ ++# INTERNAL ++function record_test { ++ if [ -z "$set_test" ] ; then ++ echo >&2 "DEJAGNU-BASH ERROR: set_test not set" ++ exit 1 ++ fi ++ # Provide the leading whitespace delimiter: ++ echo " $1: $set_test" ++ set_test="" ++} ++ ++function pass() { ++ record_test PASS ++} ++function fail() { ++ record_test FAIL ++} ++ ++ ++# Verify that the gdb output doesn't contain $1. ++function mustNotHave() { ++ local BADWORD=$1 ++ set_test gdb output contains "$BADWORD" ++ if grep -q "$BADWORD" $LOG ; then ++ fail ++ return 1 ++ fi ++ pass ++ return 0 ++} ++ ++# Verify that the gdb output contains exactly $1 $2s. ++function mustHaveCorrectAmount() { ++ local WANTEDNUMBER=$1 ++ local GOODWORD=$2 ++ local ACTUALNUMBER=$(grep "$GOODWORD" $LOG | wc -l) ++ set_test gdb output contained $ACTUALNUMBER \""$GOODWORD"\", not $WANTEDNUMBER as expected ++ if [ $ACTUALNUMBER != $WANTEDNUMBER ] ; then ++ fail ++ return 1 ++ fi ++ pass ++ return 0 ++} ++ ++# Verify that the gdb output contains seven threads ++function mustHaveSevenThreads() { ++ NTHREADS=$(egrep "^Thread [1-7] \(" $LOG | wc -l) ++ set_test gdb output contains $NTHREADS threads, not 7 as expected ++ if [ $NTHREADS != 7 ] ; then ++ fail ++ return 1 ++ fi ++ pass ++ return 0 ++} ++ ++# Verify that the gdb output has all parameters on consecutive lines ++function mustHaveSequence() { ++ SEQUENCE="$*" ++ NPARTS=$# ++ grep "$1" -A$((NPARTS - 1)) $LOG > matches.log ++ ++ while [ $# -gt 1 ] ; do ++ shift ++ ((NPARTS--)) ++ grep "$1" -A$((NPARTS - 1)) matches.log > temp.log ++ mv temp.log matches.log ++ done ++ LASTPART=$1 ++ ++ set_test gdb output does not contain the sequence: $SEQUENCE ++ if ! grep -q "$LASTPART" matches.log ; then ++ fail ++ return 1 ++ fi ++ pass ++ return 0 ++} ++ ++# Verify that $LOG contains all information we want ++function verifyLog() { ++ local FAILURES=0 ++ ++ mustNotHave '??' || ((FAILURES++)) ++ mustHaveCorrectAmount 12 threadcrash.c: || ((FAILURES++)) ++ ++ mustHaveSevenThreads || ((FAILURES++)) ++ mustHaveSequence sleep "makeSyscall (ignored=" || ((FAILURES++)) ++ ++ mustHaveSequence sleep "syscallingSighandler (signo=" "signal handler called" 0x || ((FAILURES++)) ++ mustHaveSequence pthread_kill "makeSyscallFromSighandler (ignored=" || ((FAILURES++)) ++ ++ mustHaveSequence sleep "syscallingAltSighandler (signo=" "signal handler called" 0x || ((FAILURES++)) ++ mustHaveSequence pthread_kill "makeSyscallFromAltSighandler (ignored=" || ((FAILURES++)) ++ ++ mustHaveSequence Thread "spin (ignored=" || ((FAILURES++)) ++ ++ mustHaveSequence "spinningSighandler (signo=" "signal handler called" 0x || ((FAILURES++)) ++ mustHaveSequence pthread_kill "spinFromSighandler (ignored=" || ((FAILURES++)) ++ ++ mustHaveSequence "spinningAltSighandler (signo=" "signal handler called" 0x || ((FAILURES++)) ++ mustHaveSequence pthread_kill "spinFromAltSighandler (ignored=" || ((FAILURES++)) ++ ++ mustHaveSequence Thread "main (argc=1, argv=" || ((FAILURES++)) ++ ++ return $FAILURES ++} ++ ++# Put result of debugging a core file in $LOG ++function getLogFromCore() { ++ # Make sure we get a core file ++ set_test Make sure we get a core file ++ if ! ulimit -c unlimited ; then ++ fail ++ exit 1 ++ fi ++ pass ++ ++ # Run the crasher ++ ./$(basename "$RUNME") ++ EXITCODE=$? ++ ++ # Verify that we actually crashed ++ set_test $RUNME should have been killed by a signal, got non-signal exit code $EXITCODE ++ if [ $EXITCODE -lt 128 ] ; then ++ fail ++ exit 1 ++ fi ++ pass ++ ++ # Verify that we got a core file ++ set_test $RUNME did not create a core file ++ if [ ! -r core* ] ; then ++ fail ++ exit 1 ++ fi ++ pass ++ ++ # Run gdb ++ cat > gdbscript.gdb < $LOG ++ EXITCODE=$? ++ ++ set_test gdb exited with error code ++ if [ $EXITCODE != 0 ] ; then ++ ((FAILURES++)) ++ echo >&2 gdb exited with error code $EXITCODE ++ fail ++ fi ++ pass ++} ++ ++# Put result of debugging a gcore file in $LOG ++function getLogFromGcore() { ++ # Create the core file ++ rm -f core* ++ cat > gdbscript.gdb < /dev/null ++ EXITCODE=$? ++ ++ set_test gdb exited with error code when creating gcore file ++ if [ $EXITCODE != 0 ] ; then ++ ((FAILURES++)) ++ echo >&2 gdb exited with error code $EXITCODE when creating gcore file ++ fail ++ fi ++ pass ++ ++ # Verify that we got a core file from gcore ++ set_test gdb gcore did not create a core file ++ if [ ! -r core* ] ; then ++ fail ++ exit 1 ++ fi ++ pass ++ ++ # Run gdb on the gcore file ++ cat > gdbscript.gdb < $LOG ++ EXITCODE=$? ++ ++ set_test gdb exited with error code when examining gcore file ++ if [ $EXITCODE != 0 ] ; then ++ ((FAILURES++)) ++ echo >&2 gdb exited with error code $EXITCODE when examining gcore file ++ fail ++ fi ++ pass ++} ++ ++# Put result of debugging a core file in $LOG ++function getLogFromLiveProcess() { ++ # Run gdb ++ cat > gdbscript.gdb < $LOG ++ EXITCODE=$? ++ ++ set_test gdb exited with error code ++ if [ $EXITCODE != 0 ] ; then ++ ((FAILURES++)) ++ echo >&2 gdb exited with error code $EXITCODE ++ fail ++ fi ++ pass ++} ++ ++####### Main program follows ##################### ++ ++# Make sure we don't clobber anybody else's (core) file(s) ++WORKDIR=/tmp/$PPID ++mkdir -p $WORKDIR ++cp "$RUNME" $WORKDIR ++cd $WORKDIR ++ ++# Count problems ++FAILURES=0 ++ ++echo === Testing gdb vs core file... ++pf_prefix core file ++getLogFromCore ++verifyLog ++((FAILURES+=$?)) ++pf_prefix ++echo === Core file tests done. ++ ++echo ++ ++echo === Testing gdb vs gcore file... ++pf_prefix gcore file ++getLogFromGcore ++verifyLog ++((FAILURES+=$?)) ++pf_prefix ++echo === Gcore file tests done. ++ ++echo ++ ++echo === Testing gdb vs live process... ++pf_prefix live process ++getLogFromLiveProcess ++verifyLog ++((FAILURES+=$?)) ++pf_prefix ++echo === Live process tests done. ++ ++# Executive summary ++echo ++if [ $FAILURES == 0 ] ; then ++ echo All tests passed! ++else ++ echo $FAILURES tests failed! ++ echo ++ echo Make sure the threadcrash binary contains debugging information \(build with \"gcc -g\"\). ++fi ++ ++# Clean up ++cd / ++rm -rf $WORKDIR ++ ++exit $FAILURES +Index: ./gdb/testsuite/gdb.threads/threadcrash.sh-orig +=================================================================== +RCS file: gdb/testsuite/gdb.threads/threadcrash.sh-orig +diff -N gdb/testsuite/gdb.threads/threadcrash.sh-orig +--- /dev/null 1 Jan 1970 00:00:00 -0000 ++++ ./gdb/testsuite/gdb.threads/threadcrash.sh-orig 31 Oct 2006 17:54:38 -0000 +@@ -0,0 +1,248 @@ ++#! /bin/bash ++ ++# NOTE: threadcrash.c *must* be built with debugging symbols ++# ++# The point of this shell script is to crash treadcrash.c, load the ++# resulting core file into gdb and verify that gdb can extract enough ++# information from the core file. ++# ++# The return code from this script is the number of failed tests. ++ ++LOG=gdbresult.log ++ ++if [ $# != 1 ] ; then ++ echo > /dev/stderr Syntax: $0 \ ++ exit 1 ++fi ++RUNME="$1" ++ ++# Verify that the gdb output doesn't contain $1. ++function mustNotHave() { ++ local BADWORD=$1 ++ if grep -q "$BADWORD" $LOG ; then ++ echo >> /dev/stderr WARNING: gdb output contains "$BADWORD" ++ return 1 ++ fi ++ return 0 ++} ++ ++# Verify that the gdb output contains exactly $1 $2s. ++function mustHaveCorrectAmount() { ++ local WANTEDNUMBER=$1 ++ local GOODWORD=$2 ++ local ACTUALNUMBER=$(grep "$GOODWORD" $LOG | wc -l) ++ if [ $ACTUALNUMBER != $WANTEDNUMBER ] ; then ++ echo >> /dev/stderr WARNING: gdb output contained $ACTUALNUMBER \""$GOODWORD"\", not $WANTEDNUMBER as expected ++ return 1 ++ fi ++ return 0 ++} ++ ++# Verify that the gdb output contains seven threads ++function mustHaveSevenThreads() { ++ NTHREADS=$(egrep "^Thread [1-7] \(" $LOG | wc -l) ++ if [ $NTHREADS != 7 ] ; then ++ echo >> /dev/stderr WARNING: gdb output contains $NTHREADS threads, not 7 as expected ++ return 1 ++ fi ++ return 0 ++} ++ ++# Verify that the gdb output has all parameters on consecutive lines ++function mustHaveSequence() { ++ SEQUENCE="$*" ++ NPARTS=$# ++ grep "$1" -A$((NPARTS - 1)) $LOG > matches.log ++ ++ while [ $# -gt 1 ] ; do ++ shift ++ ((NPARTS--)) ++ grep "$1" -A$((NPARTS - 1)) matches.log > temp.log ++ mv temp.log matches.log ++ done ++ LASTPART=$1 ++ ++ if ! grep -q "$LASTPART" matches.log ; then ++ echo >> /dev/stderr WARNING: gdb output does not contain the sequence: $SEQUENCE ++ return 1 ++ fi ++ return 0 ++} ++ ++# Verify that $LOG contains all information we want ++function verifyLog() { ++ local FAILURES=0 ++ ++ mustNotHave '??' || ((FAILURES++)) ++ mustHaveCorrectAmount 12 threadcrash.c: || ((FAILURES++)) ++ ++ mustHaveSevenThreads || ((FAILURES++)) ++ mustHaveSequence sleep "makeSyscall (ignored=" || ((FAILURES++)) ++ ++ mustHaveSequence sleep "syscallingSighandler (signo=" "signal handler called" 0x || ((FAILURES++)) ++ mustHaveSequence pthread_kill "makeSyscallFromSighandler (ignored=" || ((FAILURES++)) ++ ++ mustHaveSequence sleep "syscallingAltSighandler (signo=" "signal handler called" 0x || ((FAILURES++)) ++ mustHaveSequence pthread_kill "makeSyscallFromAltSighandler (ignored=" || ((FAILURES++)) ++ ++ mustHaveSequence Thread "spin (ignored=" || ((FAILURES++)) ++ ++ mustHaveSequence "spinningSighandler (signo=" "signal handler called" 0x || ((FAILURES++)) ++ mustHaveSequence pthread_kill "spinFromSighandler (ignored=" || ((FAILURES++)) ++ ++ mustHaveSequence "spinningAltSighandler (signo=" "signal handler called" 0x || ((FAILURES++)) ++ mustHaveSequence pthread_kill "spinFromAltSighandler (ignored=" || ((FAILURES++)) ++ ++ mustHaveSequence Thread "main (argc=1, argv=" || ((FAILURES++)) ++ ++ return $FAILURES ++} ++ ++# Put result of debugging a core file in $LOG ++function getLogFromCore() { ++ # Make sure we get a core file ++ ulimit -c unlimited || exit 1 ++ ++ # Run the crasher ++ ./$(basename "$RUNME") ++ EXITCODE=$? ++ ++ # Verify that we actually crashed ++ if [ $EXITCODE -lt 128 ] ; then ++ echo >> /dev/stderr ERROR: $RUNME should have been killed by a signal, got non-signal exit code $EXITCODE ++ exit 1 ++ fi ++ ++ # Verify that we got a core file ++ if [ ! -r core* ] ; then ++ echo >> /dev/stderr ERROR: $RUNME did not create a core file ++ exit 1 ++ fi ++ ++ # Run gdb ++ cat > gdbscript.gdb < $LOG ++ EXITCODE=$? ++ ++ if [ $EXITCODE != 0 ] ; then ++ ((FAILURES++)) ++ echo >> /dev/stderr WARNING: gdb exited with error code $EXITCODE ++ fi ++} ++ ++# Put result of debugging a gcore file in $LOG ++function getLogFromGcore() { ++ # Create the core file ++ rm -f core* ++ cat > gdbscript.gdb < /dev/null ++ EXITCODE=$? ++ ++ if [ $EXITCODE != 0 ] ; then ++ ((FAILURES++)) ++ echo >> /dev/stderr WARNING: gdb exited with error code $EXITCODE when creating gcore file ++ fi ++ ++ # Verify that we got a core file from gcore ++ if [ ! -r core* ] ; then ++ echo >> /dev/stderr ERROR: gdb gcore did not create a core file ++ exit 1 ++ fi ++ ++ # Run gdb on the gcore file ++ cat > gdbscript.gdb < $LOG ++ EXITCODE=$? ++ ++ if [ $EXITCODE != 0 ] ; then ++ ((FAILURES++)) ++ echo >> /dev/stderr WARNING: gdb exited with error code $EXITCODE when examining gcore file ++ fi ++} ++ ++# Put result of debugging a core file in $LOG ++function getLogFromLiveProcess() { ++ # Run gdb ++ cat > gdbscript.gdb < $LOG ++ EXITCODE=$? ++ ++ if [ $EXITCODE != 0 ] ; then ++ ((FAILURES++)) ++ echo >> /dev/stderr WARNING: gdb exited with error code $EXITCODE ++ fi ++} ++ ++####### Main program follows ##################### ++ ++# Make sure we don't clobber anybody else's (core) file(s) ++WORKDIR=/tmp/$PPID ++mkdir -p $WORKDIR ++cp "$RUNME" $WORKDIR ++cd $WORKDIR ++ ++# Count problems ++FAILURES=0 ++ ++echo === Testing gdb vs core file... ++getLogFromCore ++verifyLog ++((FAILURES+=$?)) ++echo === Core file tests done. ++ ++echo ++ ++echo === Testing gdb vs gcore file... ++getLogFromGcore ++verifyLog ++((FAILURES+=$?)) ++echo === Gcore file tests done. ++ ++echo ++ ++echo === Testing gdb vs live process... ++getLogFromLiveProcess ++verifyLog ++((FAILURES+=$?)) ++echo === Live process tests done. ++ ++# Executive summary ++echo ++if [ $FAILURES == 0 ] ; then ++ echo All tests passed! ++else ++ echo $FAILURES tests failed! ++ echo ++ echo Make sure the threadcrash binary contains debugging information \(build with \"gcc -g\"\). ++fi ++ ++# Clean up ++cd / ++rm -rf $WORKDIR ++ ++exit $FAILURES diff --git a/gdb-6.5-bz109921-DW_AT_decl_file-test.patch b/gdb-6.5-bz109921-DW_AT_decl_file-test.patch new file mode 100644 index 0000000..70be875 --- /dev/null +++ b/gdb-6.5-bz109921-DW_AT_decl_file-test.patch @@ -0,0 +1,120 @@ +https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=109921 + +It is duplicite to its upstream variant: +http://sourceware.org/ml/gdb-cvs/2007-01/msg00157.html +http://sourceware.org/ml/gdb-patches/2007-01/msg00434.html +2007-01-21 Jan Kratochvil + Daniel Jacobowitz + + * gdb.base/included.c, gdb.base/included.exp, + gdb.base/included.h: New files. + +------------------------------------------------------------------------------ + +2007-01-09 Jan Kratochvil + + * gdb.dwarf2/dw2-included.exp, gdb.dwarf2/dw2-included.c, + gdb.dwarf2/dw2-included.h: New files. + +--- /dev/null 1 Jan 1970 00:00:00 -0000 ++++ ./gdb/testsuite/gdb.dwarf2/dw2-included.c 2 Jan 2007 00:20:27 -0000 +@@ -0,0 +1,26 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2006 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ USA. */ ++ ++#include "dw2-included.h" ++ ++int ++main() ++{ ++ return 0; ++} +--- /dev/null 1 Jan 1970 00:00:00 -0000 ++++ ./gdb/testsuite/gdb.dwarf2/dw2-included.exp 2 Jan 2007 00:20:27 -0000 +@@ -0,0 +1,47 @@ ++# Copyright 2006 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++# Minimal DWARF-2 unit test ++ ++# This test can only be run on targets which support DWARF-2. ++# For now pick a sampling of likely targets. ++if {![istarget *-*-linux*] ++ && ![istarget *-*-gnu*] ++ && ![istarget *-*-elf*] ++ && ![istarget *-*-openbsd*] ++ && ![istarget arm-*-eabi*] ++ && ![istarget powerpc-*-eabi*]} { ++ return 0 ++} ++ ++set testfile "dw2-included" ++set srcfile ${testfile}.c ++set binfile ${objdir}/${subdir}/${testfile} ++ ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { ++ return -1 ++} ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++gdb_test "set listsize 1" "" ++gdb_test "list integer" "int integer;\r" ++gdb_test "ptype integer" "type = int\r" ++# Path varies depending on the build location. ++gdb_test "info variables integer" "\r\nFile \[^\r\n\]*/gdb.dwarf2/dw2-included.h:\r\nint integer;\r" +--- /dev/null 1 Jan 1970 00:00:00 -0000 ++++ ./gdb/testsuite/gdb.dwarf2/dw2-included.h 2 Jan 2007 00:20:27 -0000 +@@ -0,0 +1,20 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2006 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ USA. */ ++ ++int integer; diff --git a/gdb-6.5-bz181390-memory-address-width.patch b/gdb-6.5-bz181390-memory-address-width.patch new file mode 100644 index 0000000..894ca0c --- /dev/null +++ b/gdb-6.5-bz181390-memory-address-width.patch @@ -0,0 +1,197 @@ +https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=181390 + +2006-09-28 Jan Kratochvil + + * gdb/utils.c (paddress): Disable cutting of the printed addresses + to the target's address bit size; user wants to see everything. + * gdb/value.c (value_as_address1): Original `value_as_address'. + (value_as_address): New `value_as_address' wrapper - cut memory address + to the target's address bit size, bugreport by John Reiser. + +2008-03-02 Jan Kratochvil + + Port to GDB-6.8pre. + New testcase `gdb.arch/amd64-i386-address.exp'. + +Index: gdb-6.7.50.20080227/gdb/utils.c +=================================================================== +--- gdb-6.7.50.20080227.orig/gdb/utils.c 2008-03-02 14:28:44.000000000 +0100 ++++ gdb-6.7.50.20080227/gdb/utils.c 2008-03-02 14:35:09.000000000 +0100 +@@ -2540,6 +2540,14 @@ paddr_nz (CORE_ADDR addr) + const char * + paddress (CORE_ADDR addr) + { ++ /* Do not cut the address as the user should see all the information ++ available. Otherwise 64-bit gdb debugging 32-bit inferior would ++ report for `x/x 0xffffffffffffce70' error ++ `Cannot access memory at 0xffffce70' while the error occured just ++ because of the higher order bits 0xffffffff00000000 there. ++ This specific error no longer occurs as the address is now cut ++ during execution by `value_as_address'. */ ++#if 0 + /* Truncate address to the size of a target address, avoiding shifts + larger or equal than the width of a CORE_ADDR. The local + variable ADDR_BIT stops the compiler reporting a shift overflow +@@ -2553,6 +2561,8 @@ paddress (CORE_ADDR addr) + + if (addr_bit < (sizeof (CORE_ADDR) * HOST_CHAR_BIT)) + addr &= ((CORE_ADDR) 1 << addr_bit) - 1; ++#endif ++ + return hex_string (addr); + } + +Index: gdb-6.7.50.20080227/gdb/value.c +=================================================================== +--- gdb-6.7.50.20080227.orig/gdb/value.c 2008-01-18 18:07:40.000000000 +0100 ++++ gdb-6.7.50.20080227/gdb/value.c 2008-03-02 14:36:38.000000000 +0100 +@@ -983,11 +983,9 @@ value_as_double (struct value *val) + return foo; + } + +-/* Extract a value as a C pointer. Does not deallocate the value. +- Note that val's type may not actually be a pointer; value_as_long +- handles all the cases. */ +-CORE_ADDR +-value_as_address (struct value *val) ++/* See `value_as_address' below - core of value to C pointer extraction. */ ++static CORE_ADDR ++value_as_address1 (struct value *val) + { + /* Assume a CORE_ADDR can fit in a LONGEST (for now). Not sure + whether we want this to be true eventually. */ +@@ -1087,6 +1085,34 @@ value_as_address (struct value *val) + return unpack_long (value_type (val), value_contents (val)); + #endif + } ++ ++/* Extract a value as a C pointer. Does not deallocate the value. ++ Note that val's type may not actually be a pointer; value_as_long ++ handles all the cases. */ ++CORE_ADDR ++value_as_address (struct value *val) ++{ ++ CORE_ADDR addr; ++ int addr_bit; ++ ++ addr = value_as_address1 (val); ++ ++ /* Truncate address to the size of a target address, avoiding shifts ++ larger or equal than the width of a CORE_ADDR. The local ++ variable ADDR_BIT stops the compiler reporting a shift overflow ++ when it won't occur. */ ++ /* NOTE: This assumes that the significant address information is ++ kept in the least significant bits of ADDR - the upper bits were ++ either zero or sign extended. Should ADDRESS_TO_POINTER() or ++ some ADDRESS_TO_PRINTABLE() be used to do the conversion? */ ++ ++ addr_bit = gdbarch_addr_bit (current_gdbarch); ++ ++ if (addr_bit < (sizeof (CORE_ADDR) * HOST_CHAR_BIT)) ++ addr &= ((CORE_ADDR) 1 << addr_bit) - 1; ++ ++ return addr; ++} + + /* Unpack raw data (copied from debugee, target byte order) at VALADDR + as a long, or as a double, assuming the raw data is described +--- /dev/null 2008-03-01 10:30:54.797374318 +0100 ++++ gdb-6.7.50.20080227/gdb/testsuite/gdb.arch/amd64-i386-address.S 2008-03-02 12:47:06.000000000 +0100 +@@ -0,0 +1,32 @@ ++/* Copyright 2008 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++ Please email any bugs, comments, and/or additions to this file to: ++ bug-gdb@gnu.org ++ ++ This file is part of the gdb testsuite. ++ ++ Test UNsigned extension of the 32-bit inferior address on a 64-bit host. ++ This file is based on the work by John Reiser. ++ This file was created by Jan Kratochvil . ++ https://bugzilla.redhat.com/show_bug.cgi?id=181390 */ ++ ++_start: .globl _start ++ nop ++ int3 ++ movl %esp,%ebx ++ int3 # examining memory from $ebx fails, from $esp succeeds ++ nop ++ nop +--- /dev/null 2008-03-01 10:30:54.797374318 +0100 ++++ gdb-6.7.50.20080227/gdb/testsuite/gdb.arch/amd64-i386-address.exp 2008-03-02 12:57:11.000000000 +0100 +@@ -0,0 +1,62 @@ ++# Copyright 2008 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++# Please email any bugs, comments, and/or additions to this file to: ++# bug-gdb@gnu.org ++ ++# This file is part of the gdb testsuite. ++ ++# Test UNsigned extension of the 32-bit inferior address on a 64-bit host. ++# This file is based on the work by John Reiser. ++# This file was created by Jan Kratochvil . ++# https://bugzilla.redhat.com/show_bug.cgi?id=181390 ++ ++if {![istarget "x86_64-*-*"]} then { ++ verbose "Skipping amd64->i386 adress test." ++ return ++} ++ ++set testfile "amd64-i386-address" ++set srcfile ${testfile}.S ++set binfile ${objdir}/${subdir}/${testfile} ++ ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable [list debug "additional_flags=-m32 -nostdlib"]] != "" } { ++ untested amd64-i386-address.exp ++ return -1 ++} ++ ++# Get things started. ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++gdb_run_cmd ++ ++set test "trap stop" ++gdb_test_multiple "" $test { ++ -re "Program received signal SIGTRAP,.*_start .*$gdb_prompt $" { ++ pass $test ++ } ++} ++ ++gdb_test "stepi" ".*_start .*int3.*" ++ ++gdb_test "x/x \$esp" "0x\[0-9a-f\]*:\t0x0*1" ++ ++# Failure case would be: ++# 0xff8d7f00: Cannot access memory at address 0xff8d7f00 ++gdb_test "x/x \$ebx" "0x\[0-9a-f\]*:\t0x0*1" diff --git a/gdb-6.5-bz185337-resolve-tls-without-debuginfo-v2.patch b/gdb-6.5-bz185337-resolve-tls-without-debuginfo-v2.patch new file mode 100644 index 0000000..f183f6d --- /dev/null +++ b/gdb-6.5-bz185337-resolve-tls-without-debuginfo-v2.patch @@ -0,0 +1,261 @@ +https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=185337 + +2008-02-24 Jan Kratochvil + + Port to GDB-6.8pre. + +currently for trivial nonthreaded helloworld with no debug info up to -ggdb2 you +will get: + (gdb) p errno + [some error] + +* with -ggdb2 and less "errno" in fact does not exist anywhere as it was + compiled to "(*__errno_location ())" and the macro definition is not present. + Unfortunately gdb will find the TLS symbol and it will try to access it but + as the program has been compiled without -lpthread the TLS base register + (%gs on i386) is not setup and it will result in: + Cannot access memory at address 0x8 + +Attached suggestion patch how to deal with the most common "errno" symbol +for the most common under-ggdb3 compiled programs. + + + +2007-11-03 Jan Kratochvil + + * ./gdb/dwarf2read.c (read_partial_die, dwarf2_linkage_name): Prefer + DW_AT_MIPS_linkage_name over DW_AT_name now only for non-C. + +glibc-debuginfo-2.7-2.x86_64: /usr/lib/debug/lib64/libc.so.6.debug: + <81a2> DW_AT_name : (indirect string, offset: 0x280e): __errno_location + <81a8> DW_AT_MIPS_linkage_name: (indirect string, offset: 0x2808): *__GI___errno_location + +Index: gdb-6.8.50.20090228/gdb/gdbtypes.c +=================================================================== +--- gdb-6.8.50.20090228.orig/gdb/gdbtypes.c 2009-03-02 01:01:15.000000000 +0100 ++++ gdb-6.8.50.20090228/gdb/gdbtypes.c 2009-03-02 01:01:53.000000000 +0100 +@@ -3633,6 +3633,8 @@ gdbtypes_post_init (struct gdbarch *gdba + init_type (TYPE_CODE_INT, + gdbarch_int_bit (gdbarch) / TARGET_CHAR_BIT, + 0, "int", OBJFILE_INTERNAL); ++ builtin_type->builtin_int_ptr = ++ make_pointer_type (builtin_type->builtin_int, NULL); + builtin_type->builtin_unsigned_int = + init_type (TYPE_CODE_INT, + gdbarch_int_bit (gdbarch) / TARGET_CHAR_BIT, +@@ -3742,6 +3744,12 @@ gdbtypes_post_init (struct gdbarch *gdba + "", OBJFILE_INTERNAL); + TYPE_TARGET_TYPE (builtin_type->nodebug_text_symbol) = + builtin_type->builtin_int; ++ builtin_type->nodebug_text_symbol_errno_location = ++ init_type (TYPE_CODE_FUNC, 1, 0, ++ "", ++ OBJFILE_INTERNAL); ++ TYPE_TARGET_TYPE (builtin_type->nodebug_text_symbol_errno_location) = ++ builtin_type->builtin_int_ptr; + builtin_type->nodebug_data_symbol = + init_type (TYPE_CODE_INT, + gdbarch_int_bit (gdbarch) / HOST_CHAR_BIT, 0, +Index: gdb-6.8.50.20090228/gdb/gdbtypes.h +=================================================================== +--- gdb-6.8.50.20090228.orig/gdb/gdbtypes.h 2009-03-02 01:01:15.000000000 +0100 ++++ gdb-6.8.50.20090228/gdb/gdbtypes.h 2009-03-02 01:01:53.000000000 +0100 +@@ -1053,6 +1053,7 @@ struct builtin_type + + /* Types used for symbols with no debug information. */ + struct type *nodebug_text_symbol; ++ struct type *nodebug_text_symbol_errno_location; + struct type *nodebug_data_symbol; + struct type *nodebug_unknown_symbol; + struct type *nodebug_tls_symbol; +@@ -1065,6 +1066,7 @@ struct builtin_type + struct type *builtin_char; + struct type *builtin_short; + struct type *builtin_int; ++ struct type *builtin_int_ptr; + struct type *builtin_long; + struct type *builtin_signed_char; + struct type *builtin_unsigned_char; +Index: gdb-6.8.50.20090228/gdb/parse.c +=================================================================== +--- gdb-6.8.50.20090228.orig/gdb/parse.c 2009-03-02 01:01:15.000000000 +0100 ++++ gdb-6.8.50.20090228/gdb/parse.c 2009-03-02 01:01:53.000000000 +0100 +@@ -508,7 +508,12 @@ write_exp_msymbol (struct minimal_symbol + case mst_text: + case mst_file_text: + case mst_solib_trampoline: +- write_exp_elt_type (builtin_type (gdbarch)->nodebug_text_symbol); ++ if (builtin_type (gdbarch)->nodebug_text_symbol_errno_location != NULL ++ && strcmp (SYMBOL_LINKAGE_NAME (msymbol), "__errno_location") == 0) ++ write_exp_elt_type (builtin_type (gdbarch) ++ ->nodebug_text_symbol_errno_location); ++ else ++ write_exp_elt_type (builtin_type (gdbarch)->nodebug_text_symbol); + break; + + case mst_data: +Index: gdb-6.8.50.20090228/gdb/target.c +=================================================================== +--- gdb-6.8.50.20090228.orig/gdb/target.c 2009-03-02 01:01:44.000000000 +0100 ++++ gdb-6.8.50.20090228/gdb/target.c 2009-03-02 01:01:53.000000000 +0100 +@@ -827,6 +827,25 @@ pop_all_targets (int quitting) + pop_all_targets_above (dummy_stratum, quitting); + } + ++static int ++resolve_errno (void *arg) ++{ ++ CORE_ADDR *arg_addr = arg; ++ struct expression *expr; ++ struct cleanup *old_chain = 0; ++ struct value *val; ++ ++ expr = parse_expression ("__errno_location()"); ++ old_chain = make_cleanup (free_current_contents, &expr); ++ val = evaluate_expression (expr); ++ *arg_addr = value_as_address (val); ++ release_value (val); ++ value_free (val); ++ do_cleanups (old_chain); ++ ++ return 1; ++} ++ + /* Using the objfile specified in OBJFILE, find the address for the + current thread's thread-local storage with offset OFFSET. */ + CORE_ADDR +@@ -917,7 +936,28 @@ target_translate_tls_address (struct obj + /* It wouldn't be wrong here to try a gdbarch method, too; finding + TLS is an ABI-specific thing. But we don't do that yet. */ + else +- error (_("Cannot find thread-local variables on this target")); ++ { ++ struct minimal_symbol *msymbol; ++ ++ msymbol = lookup_minimal_symbol ("errno", NULL, NULL); ++ if (msymbol != NULL ++ && SYMBOL_VALUE_ADDRESS (msymbol) == offset ++ && (SYMBOL_OBJ_SECTION (msymbol)->objfile == objfile ++ || (objfile->separate_debug_objfile != NULL ++ && SYMBOL_OBJ_SECTION (msymbol)->objfile ++ == objfile->separate_debug_objfile) ++ || (objfile->separate_debug_objfile_backlink != NULL ++ && SYMBOL_OBJ_SECTION (msymbol)->objfile ++ == objfile->separate_debug_objfile_backlink))) ++ { ++ if (!catch_errors (resolve_errno, (void *) &addr, "", ++ RETURN_MASK_ALL)) ++ error (_("TLS symbol `errno' not resolved for non-TLS program." ++ " You should compile the program with `gcc -pthread'.")); ++ } ++ else ++ error (_("Cannot find thread-local variables on this target")); ++ } + + return addr; + } +Index: gdb-6.8.50.20090228/gdb/testsuite/gdb.dwarf2/dw2-errno.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8.50.20090228/gdb/testsuite/gdb.dwarf2/dw2-errno.c 2009-03-02 01:01:53.000000000 +0100 +@@ -0,0 +1,28 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2005, 2007 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++ Please email any bugs, comments, and/or additions to this file to: ++ bug-gdb@prep.ai.mit.edu */ ++ ++#include ++ ++int main() ++{ ++ errno = 42; ++ ++ return 0; /* breakpoint */ ++} +Index: gdb-6.8.50.20090228/gdb/testsuite/gdb.dwarf2/dw2-errno.exp +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8.50.20090228/gdb/testsuite/gdb.dwarf2/dw2-errno.exp 2009-03-02 01:01:53.000000000 +0100 +@@ -0,0 +1,67 @@ ++# Copyright 2007 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++if $tracelevel then { ++ strace $tracelevel ++} ++ ++set prms_id 0 ++set bug_id 0 ++ ++set testfile dw2-errno ++set srcfile ${testfile}.c ++set binfile ${objdir}/${subdir}/${testfile} ++ ++proc prep {} { ++ global srcdir subdir binfile ++ gdb_exit ++ gdb_start ++ gdb_reinitialize_dir $srcdir/$subdir ++ gdb_load ${binfile} ++ ++ runto_main ++ ++ gdb_breakpoint [gdb_get_line_number "breakpoint"] ++ gdb_continue_to_breakpoint "breakpoint" ++} ++ ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable "additional_flags=-g2"] != "" } { ++ untested "Couldn't compile test program" ++ return -1 ++} ++prep ++gdb_test "print errno" ".* = 42" "errno with macros=N threads=N" ++ ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable "additional_flags=-g3"] != "" } { ++ untested "Couldn't compile test program" ++ return -1 ++} ++prep ++gdb_test "print errno" ".* = 42" "errno with macros=Y threads=N" ++ ++if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable "additional_flags=-g2"] != "" } { ++ return -1 ++} ++prep ++gdb_test "print errno" ".* = 42" "errno with macros=N threads=Y" ++ ++if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable "additional_flags=-g3"] != "" } { ++ return -1 ++} ++prep ++gdb_test "print errno" ".* = 42" "errno with macros=Y threads=Y" ++ ++# TODO: Test the error on resolving ERRNO with only libc loaded. ++# Just how to find the current libc filename? diff --git a/gdb-6.5-bz190810-gdbserver-arch-advice.patch b/gdb-6.5-bz190810-gdbserver-arch-advice.patch new file mode 100644 index 0000000..fa3653c --- /dev/null +++ b/gdb-6.5-bz190810-gdbserver-arch-advice.patch @@ -0,0 +1,29 @@ +https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=190810 + + +2006-09-26 Jan Kratochvil + + * remote.c (remote_wait): Suggestion on crash due to nonmatching target. + (remote_async_wait): Likewise. + + +Index: gdb-6.8.50.20081128/gdb/remote.c +=================================================================== +--- gdb-6.8.50.20081128.orig/gdb/remote.c 2008-12-09 16:59:51.000000000 +0100 ++++ gdb-6.8.50.20081128/gdb/remote.c 2008-12-09 17:00:04.000000000 +0100 +@@ -4329,8 +4329,13 @@ Packet: '%s'\n"), + VEC_safe_push (cached_reg_t, event->regcache, &cached_reg); + } + +- if (*p != ';') +- error (_("Remote register badly formatted: %s\nhere: %s"), ++ /* It may also occur on amd64 which defaults to 32-bit i386 ++ target. gdbserver(1) is not aware of the `set architecture' ++ name itself as it is not using libbfd. */ ++ if (*p != ';') ++ error (_("Remote register badly formatted: %s\nhere: %s" ++ "\nTry to load the executable by `file' first," ++ "\nyou may also check `set/show architecture'."), + buf, p); + ++p; + } diff --git a/gdb-6.5-bz203661-emit-relocs.patch b/gdb-6.5-bz203661-emit-relocs.patch new file mode 100644 index 0000000..e09c888 --- /dev/null +++ b/gdb-6.5-bz203661-emit-relocs.patch @@ -0,0 +1,17 @@ +Index: gdb-6.5/gdb/symfile.c +=================================================================== +--- gdb-6.5.orig/gdb/symfile.c 2006-08-24 02:56:02.000000000 -0300 ++++ gdb-6.5/gdb/symfile.c 2006-08-24 02:56:36.000000000 -0300 +@@ -3739,6 +3739,12 @@ symfile_dummy_outputs (bfd *abfd, asecti + bfd_byte * + symfile_relocate_debug_section (bfd *abfd, asection *sectp, bfd_byte *buf) + { ++ /* Executable files have all the relocations already resolved. ++ * Handle files linked with --emit-relocs. ++ * http://sources.redhat.com/ml/gdb/2006-08/msg00137.html */ ++ if ((abfd->flags & EXEC_P) != 0) ++ return NULL; ++ + /* We're only interested in debugging sections with relocation + information. */ + if ((sectp->flags & SEC_RELOC) == 0) diff --git a/gdb-6.5-bz216711-clone-is-outermost.patch b/gdb-6.5-bz216711-clone-is-outermost.patch new file mode 100644 index 0000000..c8c25b5 --- /dev/null +++ b/gdb-6.5-bz216711-clone-is-outermost.patch @@ -0,0 +1,278 @@ +https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=216711 + +FIXME: This workaround should be dropped and +glibc/sysdeps/unix/sysv/linux/x86_64/clone.S should get CFI for the child +instead. + +2006-12-17 Jan Kratochvil + + * gdb/amd64-linux-tdep.c (linux_clone_code): New variable. + (LINUX_CLONE_LEN): New definition. + (amd64_linux_clone_running, amd64_linux_outermost_frame): New function. + (amd64_linux_init_abi): Initialize `outermost_frame_p'. + * gdb/i386-tdep.c (i386_gdbarch_init): Likewise. + * gdb/i386-tdep.h (gdbarch_tdep): Add `outermost_frame_p' member. + * gdb/amd64-tdep.c (amd64_frame_this_id): Call `outermost_frame_p'. + +2006-12-17 Jan Kratochvil + + * gdb.threads/bt-clone-stop.exp, gdb.threads/bt-clone-stop.c: + New file. + +2007-10-16 Jan Kratochvil + + Port to GDB-6.7. + +Index: gdb-6.8.50.20081128/gdb/amd64-linux-tdep.c +=================================================================== +--- gdb-6.8.50.20081128.orig/gdb/amd64-linux-tdep.c 2008-12-08 10:56:17.000000000 +0100 ++++ gdb-6.8.50.20081128/gdb/amd64-linux-tdep.c 2008-12-08 21:11:08.000000000 +0100 +@@ -234,6 +234,80 @@ amd64_linux_register_reggroup_p (struct + + /* Set the program counter for process PTID to PC. */ + ++/* Detect the outermost frame; during unwind of ++ #5 0x000000305cec68c3 in clone () from /lib64/tls/libc.so.6 ++ avoid the additional bogus frame ++ #6 0x0000000000000000 in ?? ++ We compare if the `linux_clone_code' block is _before_ unwound PC. */ ++ ++static const unsigned char linux_clone_code[] = ++{ ++/* libc/sysdeps/unix/sysv/linux/x86_64/clone.S */ ++/* #ifdef RESET_PID */ ++/* ... */ ++/* mov $SYS_ify(getpid), %eax */ ++/* 0xb8, 0x27, 0x00, 0x00, 0x00 */ ++/* OR */ ++/* mov $SYS_ify(getpid), %rax */ ++/* 0x48, 0xc7, 0xc0, 0x27, 0x00, 0x00, 0x00 */ ++/* so just: */ ++ 0x27, 0x00, 0x00, 0x00, ++/* syscall */ ++ 0x0f, 0x05, ++/* movl %eax, %fs:PID */ ++ 0x64, 0x89, 0x04, 0x25, 0x94, 0x00, 0x00, 0x00, ++/* movl %eax, %fs:TID */ ++ 0x64, 0x89, 0x04, 0x25, 0x90, 0x00, 0x00, 0x00, ++/* #endif */ ++/* |* Set up arguments for the function call. *| */ ++/* popq %rax |* Function to call. *| */ ++ 0x58, ++/* popq %rdi |* Argument. *| */ ++ 0x5f, ++/* call *%rax$ */ ++ 0xff, 0xd0 ++}; ++ ++#define LINUX_CLONE_LEN (sizeof linux_clone_code) ++ ++static int ++amd64_linux_clone_running (struct frame_info *this_frame) ++{ ++ CORE_ADDR pc = get_frame_pc (this_frame); ++ unsigned char buf[LINUX_CLONE_LEN]; ++ ++ if (!safe_frame_unwind_memory (this_frame, pc - LINUX_CLONE_LEN, buf, ++ LINUX_CLONE_LEN)) ++ return 0; ++ ++ if (memcmp (buf, linux_clone_code, LINUX_CLONE_LEN) != 0) ++ return 0; ++ ++ return 1; ++} ++ ++static int ++amd64_linux_outermost_frame (struct frame_info *this_frame) ++{ ++ CORE_ADDR pc = get_frame_pc (this_frame); ++ char *name; ++ ++ find_pc_partial_function (pc, &name, NULL, NULL); ++ ++ /* If we have NAME, we can optimize the search. ++ `clone' NAME still needs to have the code checked as its name may be ++ present in the user code. ++ `__clone' NAME should not be present in the user code but in the initial ++ parts of the `__clone' implementation the unwind still makes sense. ++ More detailed unwinding decision would be too much sensitive to possible ++ subtle changes in specific glibc revisions. */ ++ if (name == NULL || strcmp (name, "clone") == 0 ++ || strcmp ("__clone", name) == 0) ++ return (amd64_linux_clone_running (this_frame) != 0); ++ ++ return 0; ++} ++ + static void + amd64_linux_write_pc (struct regcache *regcache, CORE_ADDR pc) + { +@@ -272,6 +346,8 @@ amd64_linux_init_abi (struct gdbarch_inf + tdep->sc_reg_offset = amd64_linux_sc_reg_offset; + tdep->sc_num_regs = ARRAY_SIZE (amd64_linux_sc_reg_offset); + ++ tdep->outermost_frame_p = amd64_linux_outermost_frame; ++ + /* GNU/Linux uses SVR4-style shared libraries. */ + set_solib_svr4_fetch_link_map_offsets + (gdbarch, svr4_lp64_fetch_link_map_offsets); +Index: gdb-6.8.50.20081128/gdb/amd64-tdep.c +=================================================================== +--- gdb-6.8.50.20081128.orig/gdb/amd64-tdep.c 2008-12-08 10:56:17.000000000 +0100 ++++ gdb-6.8.50.20081128/gdb/amd64-tdep.c 2008-12-08 21:05:12.000000000 +0100 +@@ -1044,11 +1044,16 @@ amd64_frame_this_id (struct frame_info * + { + struct amd64_frame_cache *cache = + amd64_frame_cache (this_frame, this_cache); ++ struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (this_frame)); + + /* This marks the outermost frame. */ + if (cache->base == 0) + return; + ++ /* Detect OS dependent outermost frames; such as `clone'. */ ++ if (tdep->outermost_frame_p && tdep->outermost_frame_p (this_frame)) ++ return; ++ + (*this_id) = frame_id_build (cache->base + 16, cache->pc); + } + +Index: gdb-6.8.50.20081128/gdb/i386-tdep.c +=================================================================== +--- gdb-6.8.50.20081128.orig/gdb/i386-tdep.c 2008-12-08 10:56:17.000000000 +0100 ++++ gdb-6.8.50.20081128/gdb/i386-tdep.c 2008-12-08 11:00:43.000000000 +0100 +@@ -2698,6 +2698,9 @@ i386_gdbarch_init (struct gdbarch_info i + tdep->sc_pc_offset = -1; + tdep->sc_sp_offset = -1; + ++ /* Unwinding stops on i386 automatically. */ ++ tdep->outermost_frame_p = NULL; ++ + /* The format used for `long double' on almost all i386 targets is + the i387 extended floating-point format. In fact, of all targets + in the GCC 2.95 tree, only OSF/1 does it different, and insists +Index: gdb-6.8.50.20081128/gdb/i386-tdep.h +=================================================================== +--- gdb-6.8.50.20081128.orig/gdb/i386-tdep.h 2008-12-08 10:56:17.000000000 +0100 ++++ gdb-6.8.50.20081128/gdb/i386-tdep.h 2008-12-08 21:07:47.000000000 +0100 +@@ -106,6 +106,9 @@ struct gdbarch_tdep + /* ISA-specific data types. */ + struct type *i386_mmx_type; + struct type *i386_sse_type; ++ ++ /* Detect OS dependent outermost frames; such as `clone'. */ ++ int (*outermost_frame_p) (struct frame_info *this_frame); + }; + + /* Floating-point registers. */ +Index: gdb-6.8.50.20081128/gdb/testsuite/gdb.threads/bt-clone-stop.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8.50.20081128/gdb/testsuite/gdb.threads/bt-clone-stop.c 2008-12-08 11:00:43.000000000 +0100 +@@ -0,0 +1,39 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2006 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ++ MA 02110-1301, USA. */ ++ ++ ++#include ++#include ++#include ++ ++ ++void *threader (void *arg) ++{ ++ assert (0); ++ return NULL; ++} ++ ++int main (void) ++{ ++ pthread_t t1; ++ ++ pthread_create (&t1, NULL, threader, (void *) NULL); ++ for (;;) ++ pause(); ++} +Index: gdb-6.8.50.20081128/gdb/testsuite/gdb.threads/bt-clone-stop.exp +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8.50.20081128/gdb/testsuite/gdb.threads/bt-clone-stop.exp 2008-12-08 11:00:43.000000000 +0100 +@@ -0,0 +1,61 @@ ++# Copyright 2006 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++# Backtraced `clone' must not have `PC == 0' as its previous frame. ++ ++if $tracelevel then { ++ strace $tracelevel ++} ++ ++set testfile bt-clone-stop ++set srcfile ${testfile}.c ++set binfile ${objdir}/${subdir}/${testfile} ++if { [gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { ++ untested "Couldn't compile test program" ++ return -1 ++} ++ ++# Get things started. ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++# threader: threader.c:8: threader: Assertion `0' failed. ++# Program received signal SIGABRT, Aborted. ++ ++gdb_test "run" \ ++ "Program received signal SIGABRT.*" \ ++ "run" ++ ++# Former gdb unwind (the first function is `clone'): ++# #5 0x0000003421ecd62d in ?? () from /lib64/libc.so.6 ++# #6 0x0000000000000000 in ?? () ++# (gdb) ++# Tested `amd64_linux_outermost_frame' functionality should omit the line `#6'. ++# ++# Two `-re' cases below must be in this order (1st is a subset of the 2nd one). ++# Unhandled case below should not happen and it is fortunately handled by ++# `amd64_linux_outermost_frame' as FAIL (and result `0x0 entry output invalid'). ++gdb_test_multiple "bt" "0x0 entry output invalid" { ++ -re "in threader \\(.*\n#\[0-9\]* *0x0* in .*$gdb_prompt $" { ++ fail "0x0 entry found" ++ } ++ -re "in threader \\(.*$gdb_prompt $" { ++ pass "0x0 entry not found" ++ } ++} diff --git a/gdb-6.5-bz218379-ppc-solib-trampoline-fix.patch b/gdb-6.5-bz218379-ppc-solib-trampoline-fix.patch new file mode 100644 index 0000000..4fb26b0 --- /dev/null +++ b/gdb-6.5-bz218379-ppc-solib-trampoline-fix.patch @@ -0,0 +1,19 @@ +https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=218379 + + +Index: gdb-6.8.50.20081128/gdb/minsyms.c +=================================================================== +--- gdb-6.8.50.20081128.orig/gdb/minsyms.c 2008-10-01 18:56:52.000000000 +0200 ++++ gdb-6.8.50.20081128/gdb/minsyms.c 2008-12-02 23:24:27.000000000 +0100 +@@ -544,6 +544,11 @@ lookup_minimal_symbol_by_pc_section_1 (C + don't fill the bfd_section member, so don't + throw away symbols on those platforms. */ + && SYMBOL_OBJ_SECTION (&msymbol[hi]) != NULL ++ /* Don't ignore symbols for solib trampolines. ++ Limit its sideeffects - only for non-0 sized trampolines. ++ Red Hat Bug 200533 with its regression Bug 218379. */ ++ && (MSYMBOL_TYPE (&msymbol[hi]) != mst_solib_trampoline ++ || MSYMBOL_SIZE (&msymbol[hi])) + && (!matching_obj_sections + (SYMBOL_OBJ_SECTION (&msymbol[hi]), section))) + { diff --git a/gdb-6.5-bz218379-ppc-solib-trampoline-test.patch b/gdb-6.5-bz218379-ppc-solib-trampoline-test.patch new file mode 100644 index 0000000..bb6f3f1 --- /dev/null +++ b/gdb-6.5-bz218379-ppc-solib-trampoline-test.patch @@ -0,0 +1,91 @@ +https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=218379 + + +--- /dev/null 2006-12-17 14:18:21.881669220 -0500 ++++ gdb-6.5/gdb/testsuite/gdb.base/step-over-trampoline.exp 2006-12-17 16:52:51.000000000 -0500 +@@ -0,0 +1,54 @@ ++# Copyright 2006 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++if $tracelevel then { ++ strace $tracelevel ++} ++ ++set testfile step-over-trampoline ++set srcfile ${testfile}.c ++set binfile ${objdir}/${subdir}/${testfile} ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { ++ untested "Couldn't compile test program" ++ return -1 ++} ++ ++# Get things started. ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++# For C programs, "start" should stop in main(). ++ ++gdb_test "start" \ ++ "main \\(\\) at .*$srcfile.*" \ ++ "start" ++ ++# main () at hello2.c:5 ++# 5 puts("hello world\n"); ++# (gdb) next ++# 0x100007e0 in call___do_global_ctors_aux () ++ ++gdb_test_multiple "next" "invalid `next' output" { ++ -re "\nhello world.*return 0;.*" { ++ pass "stepped over" ++ } ++ -re " in call___do_global_ctors_aux \\(\\).*" { ++ fail "stepped into trampoline" ++ } ++} +--- /dev/null 2006-12-17 14:18:21.881669220 -0500 ++++ gdb-6.5/gdb/testsuite/gdb.base/step-over-trampoline.c 2006-12-17 16:18:12.000000000 -0500 +@@ -0,0 +1,28 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2006 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++ Please email any bugs, comments, and/or additions to this file to: ++ bug-gdb@prep.ai.mit.edu */ ++ ++#include ++ ++int main (void) ++{ ++ puts ("hello world"); ++ return 0; ++} diff --git a/gdb-6.5-bz218379-solib-trampoline-lookup-lock-fix.patch b/gdb-6.5-bz218379-solib-trampoline-lookup-lock-fix.patch new file mode 100644 index 0000000..5fee1e6 --- /dev/null +++ b/gdb-6.5-bz218379-solib-trampoline-lookup-lock-fix.patch @@ -0,0 +1,21 @@ +https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=218379 + + +Index: gdb-6.8/gdb/symtab.c +=================================================================== +--- gdb-6.8.orig/gdb/symtab.c 2008-02-05 23:17:40.000000000 +0100 ++++ gdb-6.8/gdb/symtab.c 2008-07-14 10:27:32.000000000 +0200 +@@ -2132,6 +2132,13 @@ find_pc_sect_line (CORE_ADDR pc, struct + /* See above comment about why warning is commented out */ + /* warning ("In stub for %s; unable to find real function/line info", SYMBOL_LINKAGE_NAME (msymbol)) */ ; + /* fall through */ ++ /* `msymbol' trampoline may be located before its .text symbol ++ but this text symbol may be the address we were looking for. ++ Avoid `find_pc_sect_line'<->`find_pc_line' infinite loop. ++ Red Hat Bug 218379. */ ++ else if (SYMBOL_VALUE (mfunsym) == pc) ++ warning ("In stub for %s (0x%s); interlocked, please submit the binary to http://bugzilla.redhat.com", SYMBOL_LINKAGE_NAME (msymbol), paddr (pc)); ++ /* fall through */ + else + return find_pc_line (SYMBOL_VALUE_ADDRESS (mfunsym), 0); + } diff --git a/gdb-6.5-bz243845-stale-testing-zombie-test.patch b/gdb-6.5-bz243845-stale-testing-zombie-test.patch new file mode 100644 index 0000000..aa514c2 --- /dev/null +++ b/gdb-6.5-bz243845-stale-testing-zombie-test.patch @@ -0,0 +1,86 @@ +diff -u -ruNp gdb-6.3-unpatched/gdb/testsuite/gdb.base/tracefork-zombie.exp gdb-6.3/gdb/testsuite/gdb.base/tracefork-zombie.exp +--- gdb-6.3-unpatched/gdb/testsuite/gdb.base/tracefork-zombie.exp 1969-12-31 19:00:00.000000000 -0500 ++++ gdb-6.3/gdb/testsuite/gdb.base/tracefork-zombie.exp 2007-07-31 13:04:12.000000000 -0400 +@@ -0,0 +1,82 @@ ++# Copyright 2007 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ ++ ++if $tracelevel then { ++ strace $tracelevel ++} ++ ++set prms_id 0 ++set bug_id 0 ++ ++# are we on a target board ++if [is_remote target] then { ++ return 0 ++} ++ ++# Start the program running and then wait for a bit, to be sure ++# that it can be attached to. ++ ++gdb_exit ++gdb_start ++gdb_load sleep ++ ++set gdb_pid [exp_pid -i [board_info host fileid]] ++set test "identified the child GDB" ++if {$gdb_pid != "" && $gdb_pid > 0} { ++ pass $test ++ verbose -log "Child GDB PID $gdb_pid" ++} else { ++ fail $test ++} ++ ++set testpid [eval exec sleep 10 &] ++exec sleep 2 ++ ++set test "attach" ++gdb_test_multiple "attach $testpid" "$test" { ++ -re "Attaching to program.*`?.*'?, process $testpid..*$gdb_prompt $" { ++ pass "$test" ++ } ++ -re "Attaching to program.*`?.*\.exe'?, process $testpid.*\[Switching to thread $testpid\..*\].*$gdb_prompt $" { ++ # Response expected on Cygwin ++ pass "$test" ++ } ++} ++ ++# Some time to let GDB spawn its testing child. ++exec sleep 2 ++ ++set found none ++foreach procpid [glob -directory /proc -type d {[0-9]*}] { ++ if {[catch {open $procpid/status} statusfi]} { ++ continue ++ } ++ set status [read $statusfi] ++ close $statusfi ++ if {1 ++ && [regexp -line {^Name:\tgdb$} $status] ++ && [regexp -line {^PPid:\t1$} $status] ++ && [regexp -line "^TracerPid:\t$gdb_pid$" $status]} { ++ set found $procpid ++ verbose -log "Found linux_test_for_tracefork zombie PID $procpid" ++ } ++} ++set test "linux_test_for_tracefork leaves no zombie" ++if {$found eq {none}} { ++ pass $test ++} else { ++ fail $test ++} diff --git a/gdb-6.5-dwarf-stack-overflow.patch b/gdb-6.5-dwarf-stack-overflow.patch new file mode 100644 index 0000000..476bac2 --- /dev/null +++ b/gdb-6.5-dwarf-stack-overflow.patch @@ -0,0 +1,52 @@ +for gdb/ChangeLog: +2006-08-22 Will Drewry + Tavis Ormandy + + * dwarf2read.c (decode_locdesc): Enforce location description stack + boundaries. + * dwarfread.c (locval): Likewise. + +2007-10-15 Jan Kratochvil + + Port to GDB-6.7. + +Index: gdb-6.7/gdb/dwarf2read.c +=================================================================== +--- gdb-6.7.orig/gdb/dwarf2read.c 2007-10-15 00:08:30.000000000 +0200 ++++ gdb-6.7/gdb/dwarf2read.c 2007-10-15 21:42:43.000000000 +0200 +@@ -9070,8 +9070,7 @@ dwarf2_fundamental_type (struct objfile + callers will only want a very basic result and this can become a + complaint. + +- Note that stack[0] is unused except as a default error return. +- Note that stack overflow is not yet handled. */ ++ Note that stack[0] is unused except as a default error return. */ + + static CORE_ADDR + decode_locdesc (struct dwarf_block *blk, struct dwarf2_cu *cu) +@@ -9088,7 +9087,7 @@ decode_locdesc (struct dwarf_block *blk, + + i = 0; + stacki = 0; +- stack[stacki] = 0; ++ stack[++stacki] = 0; + + while (i < size) + { +@@ -9270,6 +9269,16 @@ decode_locdesc (struct dwarf_block *blk, + dwarf_stack_op_name (op)); + return (stack[stacki]); + } ++ /* Enforce maximum stack depth of size-1 to avoid ++stacki writing ++ outside of the allocated space. Also enforce minimum > 0. ++ -- wad@google.com 14 Aug 2006 */ ++ if (stacki >= sizeof (stack) / sizeof (*stack) - 1) ++ internal_error (__FILE__, __LINE__, ++ _("location description stack too deep: %d"), ++ stacki); ++ if (stacki <= 0) ++ internal_error (__FILE__, __LINE__, ++ _("location description stack too shallow")); + } + return (stack[stacki]); + } diff --git a/gdb-6.5-gcore-buffer-limit-test.patch b/gdb-6.5-gcore-buffer-limit-test.patch new file mode 100644 index 0000000..9442198 --- /dev/null +++ b/gdb-6.5-gcore-buffer-limit-test.patch @@ -0,0 +1,146 @@ +diff -u -X /home/jkratoch/.diffi.list -ruNp gdb-6.5/gdb/testsuite/gdb.base/gcore-excessive-memory.c gdb-6.5-unknown/gdb/testsuite/gdb.base/gcore-excessive-memory.c +--- gdb-6.5/gdb/testsuite/gdb.base/gcore-excessive-memory.c 1970-01-01 01:00:00.000000000 +0100 ++++ gdb-6.5-unknown/gdb/testsuite/gdb.base/gcore-excessive-memory.c 2008-01-08 11:25:45.000000000 +0100 +@@ -0,0 +1,37 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2008 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++ Please email any bugs, comments, and/or additions to this file to: ++ bug-gdb@prep.ai.mit.edu */ ++ ++#include ++#include ++ ++#define MEGS 64 ++ ++int main() ++{ ++ void *mem; ++ ++ mem = malloc (MEGS * 1024ULL * 1024ULL); ++ ++ for (;;) ++ sleep (1); ++ ++ return 0; ++} +diff -u -X /home/jkratoch/.diffi.list -ruNp gdb-6.5/gdb/testsuite/gdb.base/gcore-excessive-memory.exp gdb-6.5-unknown/gdb/testsuite/gdb.base/gcore-excessive-memory.exp +--- gdb-6.5/gdb/testsuite/gdb.base/gcore-excessive-memory.exp 1970-01-01 01:00:00.000000000 +0100 ++++ gdb-6.5-unknown/gdb/testsuite/gdb.base/gcore-excessive-memory.exp 2008-01-08 11:47:32.000000000 +0100 +@@ -0,0 +1,101 @@ ++# Copyright 2008 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++if $tracelevel then { ++ strace $tracelevel ++} ++ ++set prms_id 0 ++set bug_id 0 ++ ++set testfile gcore-excessive-memory ++set srcfile ${testfile}.c ++set shfile ${objdir}/${subdir}/${testfile}-gdb.sh ++set corefile ${objdir}/${subdir}/${testfile}.core ++set binfile ${objdir}/${subdir}/${testfile} ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { ++ untested "Couldn't compile test program" ++ return -1 ++} ++ ++set f [open "|getconf PAGESIZE" "r"] ++gets $f pagesize ++close $f ++ ++set pid_of_bin [eval exec $binfile &] ++sleep 2 ++ ++# Get things started. ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++set pid_of_gdb [exp_pid -i [board_info host fileid]] ++ ++gdb_test "attach $pid_of_bin" "Attaching to .*" "attach" ++gdb_test "up 99" "in main .*" "verify we can get to main" ++ ++proc memory_v_pages_get {} { ++ global pid_of_gdb pagesize ++ set fd [open "/proc/$pid_of_gdb/statm"] ++ gets $fd line ++ close $fd ++ # number of pages of virtual memory ++ scan $line "%d" drs ++ return $drs ++} ++ ++set pages_found [memory_v_pages_get] ++ ++# It must be definitely less than `MEGS' of `gcore-excessive-memory.c'. ++set mb_gcore_reserve 4 ++verbose -log "pages_found = $pages_found, mb_gcore_reserve = $mb_gcore_reserve" ++set kb_found [expr $pages_found * $pagesize / 1024] ++set kb_permit [expr $kb_found + 1 * 1024 + $mb_gcore_reserve * 1024] ++verbose -log "kb_found = $kb_found, kb_permit = $kb_permit" ++ ++# Create the ulimit wrapper. ++set f [open $shfile "w"] ++puts $f "#! /bin/sh" ++puts $f "ulimit -v $kb_permit" ++puts $f "exec $GDB \"\$@\"" ++close $f ++remote_exec host "chmod +x $shfile" ++ ++gdb_exit ++set GDBold $GDB ++set GDB "$shfile" ++gdb_start ++set GDB $GDBold ++ ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++set pid_of_gdb [exp_pid -i [board_info host fileid]] ++ ++gdb_test "attach $pid_of_bin" "Attaching to .*" "attach" ++gdb_test "up 99" "in main .*" "verify we can get to main" ++ ++verbose -log "kb_found before gcore = [expr [memory_v_pages_get] * $pagesize / 1024]" ++ ++gdb_test "gcore $corefile" "Saved corefile \[^\n\r\]*" "Save the core file" ++ ++verbose -log "kb_found after gcore = [expr [memory_v_pages_get] * $pagesize / 1024]" ++ ++# Cleanup. ++exec kill -9 $pid_of_bin diff --git a/gdb-6.5-gcore-i386-on-amd64.patch b/gdb-6.5-gcore-i386-on-amd64.patch new file mode 100644 index 0000000..b4fb9c5 --- /dev/null +++ b/gdb-6.5-gcore-i386-on-amd64.patch @@ -0,0 +1,847 @@ +2006-10-01 Jan Kratochvil + Fujitsu + + * amd64-linux-nat.c: Support new linux_elfcore_write_prpsinfo, + linux_elfcore_write_prstatus, linux_elfcore_write_prfpreg. + (i386_linux_gregset32_reg_offset): New mapping for i386 on amd64. + * gcore.c (gcore_create_callback): Comment vdso Linux kernel bug. + * configure.ac: Check for , . + * configure, config.in: Regenerated. + * gdb_user32.h, gdb_procfs32.h: Define 32-bit core files even for + 64-bit gdb, provide fallbacks for and . + * linux-nat.c: Virtualize `elfcore_*' by (*`linux_elfcore_*'). + (linux_nat_do_thread_registers): Likewise. + (linux_nat_make_corefile_notes): Likewise. + * linux-nat.h: Likewise. + * Makefile.in: Dependencies updated. + +2007-10-16 Jan Kratochvil + + Port to GDB-6.7. + +2008-02-24 Jan Kratochvil + + Port to GDB-6.8pre. + +Index: gdb-6.8.50.20081214/gdb/amd64-linux-nat.c +=================================================================== +--- gdb-6.8.50.20081214.orig/gdb/amd64-linux-nat.c 2008-12-14 21:17:01.000000000 +0100 ++++ gdb-6.8.50.20081214/gdb/amd64-linux-nat.c 2008-12-14 21:24:19.000000000 +0100 +@@ -50,6 +50,9 @@ + #include "amd64-tdep.h" + #include "i386-linux-tdep.h" + #include "amd64-nat.h" ++#include "i387-tdep.h" ++#include "elf-bfd.h" ++#include "gdb_procfs32.h" + + /* Mapping between the general-purpose registers in GNU/Linux x86-64 + `struct user' format and GDB's register cache layout. */ +@@ -84,6 +87,35 @@ static int amd64_linux_gregset64_reg_off + GNU/Linux i386 registers are all 32-bit, but since we're + little-endian we get away with that. */ + ++/* This info is not reusable from "i386-linux-nat.c" as gdb itself runs in ++ 64-bit mode and so ptrace(2) has 64-bit structure layout. ++ Just the corefile being generated has 32-bit layout so we need to do ++ a conversion specific to the i386-on-amd64 compatibility mode. */ ++static int i386_linux_gregset32_reg_offset[] = ++{ ++ 6 * 4, /* %eax */ ++ 1 * 4, /* %ecx */ ++ 2 * 4, /* %edx */ ++ 0 * 4, /* %ebx */ ++ 15 * 4, /* %esp */ ++ 5 * 4, /* %ebp */ ++ 3 * 4, /* %esi */ ++ 4 * 4, /* %edi */ ++ 12 * 4, /* %eip */ ++ 14 * 4, /* %eflags */ ++ 13 * 4, /* %cs */ ++ 16 * 4, /* %ss */ ++ 7 * 4, /* %ds */ ++ 8 * 4, /* %es */ ++ 9 * 4, /* %fs */ ++ 10 * 4, /* %gs */ ++ -1, -1, -1, -1, -1, -1, -1, -1, ++ -1, -1, -1, -1, -1, -1, -1, -1, ++ -1, -1, -1, -1, -1, -1, -1, -1, ++ -1, ++ 11 * 4 /* "orig_eax" */ ++}; ++ + /* From on GNU/Linux i386. */ + static int amd64_linux_gregset32_reg_offset[] = + { +@@ -102,6 +134,96 @@ static int amd64_linux_gregset32_reg_off + }; + + ++/* This functions make ELF32 32-bit elfcore note sections ++ on amd64 environment. */ ++ ++static char * ++amd64_linux_elfcore_write_prpsinfo (bfd *abfd, char *buf, int *bufsiz, ++ const char *fname, const char *psargs) ++{ ++ if (gdbarch_ptr_bit(current_gdbarch) == 32) ++ { ++ int note_type; ++ char *note_name = "CORE"; ++ struct elf_prpsinfo32 data; ++ note_type = NT_PRPSINFO; ++ ++ memset (&data, 0, sizeof (data)); ++ strncpy (data.pr_fname, fname, sizeof (data.pr_fname)); ++ strncpy (data.pr_psargs, psargs, sizeof (data.pr_psargs)); ++ return elfcore_write_note (abfd, buf, bufsiz, ++ note_name, note_type, &data, sizeof (data)); ++ } ++ else ++ return elfcore_write_prpsinfo (abfd, buf, bufsiz, fname, psargs); ++} ++ ++static void ++amd64_linux_set_registers (const gdb_byte *gregs, gdb_byte *buf) ++{ ++ int i; ++ /* Copy the i386 registers in the amd64 layout into i386 layout. */ ++ for (i = 0; i < I386_NUM_GREGS; i++) ++ memcpy(buf + i386_linux_gregset32_reg_offset[i], ++ gregs + amd64_linux_gregset32_reg_offset[i], 4); ++ for (i = I386_CS_REGNUM; i <= I386_GS_REGNUM; i++) ++ memcpy(buf + i386_linux_gregset32_reg_offset[i], ++ gregs + amd64_linux_gregset32_reg_offset[i], 4); ++} ++ ++static char * ++amd64_linux_elfcore_write_prstatus (bfd *abfd, char *buf, int *bufsiz, ++ long pid, int cursig, const void *gregs) ++{ ++ if (gdbarch_ptr_bit(current_gdbarch) == 32) ++ { ++ char *note_name = "CORE"; ++ struct elf_prstatus32 prstat; ++ memset (&prstat, 0, sizeof (prstat)); ++ prstat.pr_pid = pid; ++ prstat.pr_cursig = cursig; ++ amd64_linux_set_registers (gregs, (gdb_byte *) &prstat.pr_reg); ++ return elfcore_write_note (abfd, buf, bufsiz, note_name, ++ NT_PRSTATUS, &prstat, sizeof (prstat)); ++ } ++ else ++ return elfcore_write_prstatus (abfd, buf, bufsiz, pid, cursig, gregs); ++} ++ ++static char * ++amd64_elfcore_write_prxfpreg32 (bfd *abfd, char *buf, int *bufsiz, ++ struct regcache *regcache) ++{ ++ char *note_name = "LINUX"; ++ elf_fpxregset32_t fpxregs32; ++ ++ i387_collect_fxsave (regcache, -1, &fpxregs32); ++ return elfcore_write_note(abfd, buf, bufsiz, ++ note_name, NT_PRXFPREG, &fpxregs32, ++ sizeof(fpxregs32)); ++} ++ ++static char * ++amd64_linux_elfcore_write_prfpreg (bfd *abfd, char *buf, ++ int *bufsiz, const void *fpregs, int size, ++ struct regcache *regcache) ++{ ++ if (gdbarch_ptr_bit(current_gdbarch) == 32) ++ { ++ char *note_name = "CORE"; ++ elf_fpregset32_t fpregs32; ++ ++ i387_collect_fsave (regcache, -1, &fpregs32); ++ buf = elfcore_write_note(abfd, buf, bufsiz, note_name, ++ NT_FPREGSET, &fpregs32, sizeof(fpregs32)); ++ ++ return amd64_elfcore_write_prxfpreg32 (abfd, buf, bufsiz, regcache); ++ } ++ else ++ return elfcore_write_prfpreg (abfd, buf, bufsiz, fpregs, size); ++} ++ ++ + /* Transfering the general-purpose registers between GDB, inferiors + and core files. */ + +@@ -431,6 +553,11 @@ _initialize_amd64_linux_nat (void) + t->to_fetch_registers = amd64_linux_fetch_inferior_registers; + t->to_store_registers = amd64_linux_store_inferior_registers; + ++ /* This functions make elfcore note sections. */ ++ linux_elfcore_write_prpsinfo = amd64_linux_elfcore_write_prpsinfo; ++ linux_elfcore_write_prstatus = amd64_linux_elfcore_write_prstatus; ++ linux_elfcore_write_prfpreg = amd64_linux_elfcore_write_prfpreg; ++ + /* Register the target. */ + linux_nat_add_target (t); + linux_nat_set_new_thread (t, amd64_linux_new_thread); +Index: gdb-6.8.50.20081214/gdb/config.in +=================================================================== +--- gdb-6.8.50.20081214.orig/gdb/config.in 2008-12-14 21:17:01.000000000 +0100 ++++ gdb-6.8.50.20081214/gdb/config.in 2008-12-14 21:34:50.000000000 +0100 +@@ -136,6 +136,9 @@ + /* Define to 1 if you have the header file. */ + #undef HAVE_ELF_HP_H + ++/* Define if struct elf_prstatus32 is available. */ ++#undef HAVE_ELF_PRSTATUS32 ++ + /* Define to 1 if your system has the etext variable. */ + #undef HAVE_ETEXT + +@@ -465,6 +468,9 @@ + /* Define to 1 if you have the header file. */ + #undef HAVE_SYS_POLL_H + ++/* Define to 1 if you have the header file. */ ++#undef HAVE_SYS_PROCFS32_H ++ + /* Define to 1 if you have the header file. */ + #undef HAVE_SYS_PROCFS_H + +@@ -492,6 +498,9 @@ + /* Define to 1 if you have the header file. */ + #undef HAVE_SYS_TYPES_H + ++/* Define to 1 if you have the header file. */ ++#undef HAVE_SYS_USER32_H ++ + /* Define to 1 if you have the header file. */ + #undef HAVE_SYS_USER_H + +Index: gdb-6.8.50.20081214/gdb/configure +=================================================================== +--- gdb-6.8.50.20081214.orig/gdb/configure 2008-12-14 21:17:01.000000000 +0100 ++++ gdb-6.8.50.20081214/gdb/configure 2008-12-14 21:33:30.000000000 +0100 +@@ -12026,6 +12026,268 @@ _ACEOF + + fi + ++ ++ ++for ac_header in sys/user32.h sys/procfs32.h ++do ++as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` ++if eval "test \"\${$as_ac_Header+set}\" = set"; then ++ echo "$as_me:$LINENO: checking for $ac_header" >&5 ++echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 ++if eval "test \"\${$as_ac_Header+set}\" = set"; then ++ echo $ECHO_N "(cached) $ECHO_C" >&6 ++fi ++echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 ++echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 ++else ++ # Is the header compilable? ++echo "$as_me:$LINENO: checking $ac_header usability" >&5 ++echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 ++cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++$ac_includes_default ++#include <$ac_header> ++_ACEOF ++rm -f conftest.$ac_objext ++if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ++ (eval $ac_compile) 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } && ++ { ac_try='test -z "$ac_c_werror_flag" ++ || test ! -s conftest.err' ++ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 ++ (eval $ac_try) 2>&5 ++ ac_status=$? ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); }; } && ++ { ac_try='test -s conftest.$ac_objext' ++ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 ++ (eval $ac_try) 2>&5 ++ ac_status=$? ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); }; }; then ++ ac_header_compiler=yes ++else ++ echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ac_header_compiler=no ++fi ++rm -f conftest.err conftest.$ac_objext conftest.$ac_ext ++echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 ++echo "${ECHO_T}$ac_header_compiler" >&6 ++ ++# Is the header present? ++echo "$as_me:$LINENO: checking $ac_header presence" >&5 ++echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 ++cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++#include <$ac_header> ++_ACEOF ++if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 ++ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } >/dev/null; then ++ if test -s conftest.err; then ++ ac_cpp_err=$ac_c_preproc_warn_flag ++ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag ++ else ++ ac_cpp_err= ++ fi ++else ++ ac_cpp_err=yes ++fi ++if test -z "$ac_cpp_err"; then ++ ac_header_preproc=yes ++else ++ echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ ac_header_preproc=no ++fi ++rm -f conftest.err conftest.$ac_ext ++echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 ++echo "${ECHO_T}$ac_header_preproc" >&6 ++ ++# So? What about this header? ++case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in ++ yes:no: ) ++ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 ++echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} ++ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 ++echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} ++ ac_header_preproc=yes ++ ;; ++ no:yes:* ) ++ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 ++echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} ++ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 ++echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} ++ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 ++echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} ++ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 ++echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} ++ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 ++echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} ++ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 ++echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} ++ ( ++ cat <<\_ASBOX ++## ------------------------------------------ ## ++## Report this to the AC_PACKAGE_NAME lists. ## ++## ------------------------------------------ ## ++_ASBOX ++ ) | ++ sed "s/^/$as_me: WARNING: /" >&2 ++ ;; ++esac ++echo "$as_me:$LINENO: checking for $ac_header" >&5 ++echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 ++if eval "test \"\${$as_ac_Header+set}\" = set"; then ++ echo $ECHO_N "(cached) $ECHO_C" >&6 ++else ++ eval "$as_ac_Header=\$ac_header_preproc" ++fi ++echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 ++echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 ++ ++fi ++if test `eval echo '${'$as_ac_Header'}'` = yes; then ++ cat >>confdefs.h <<_ACEOF ++#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 ++_ACEOF ++ ++fi ++ ++done ++ ++echo "$as_me:$LINENO: checking for struct elf_prstatus32.pr_reg" >&5 ++echo $ECHO_N "checking for struct elf_prstatus32.pr_reg... $ECHO_C" >&6 ++if test "${ac_cv_member_struct_elf_prstatus32_pr_reg+set}" = set; then ++ echo $ECHO_N "(cached) $ECHO_C" >&6 ++else ++ cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++#include ++ ++int ++main () ++{ ++static struct elf_prstatus32 ac_aggr; ++if (ac_aggr.pr_reg) ++return 0; ++ ; ++ return 0; ++} ++_ACEOF ++rm -f conftest.$ac_objext ++if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ++ (eval $ac_compile) 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } && ++ { ac_try='test -z "$ac_c_werror_flag" ++ || test ! -s conftest.err' ++ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 ++ (eval $ac_try) 2>&5 ++ ac_status=$? ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); }; } && ++ { ac_try='test -s conftest.$ac_objext' ++ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 ++ (eval $ac_try) 2>&5 ++ ac_status=$? ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); }; }; then ++ ac_cv_member_struct_elf_prstatus32_pr_reg=yes ++else ++ echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++#include ++ ++int ++main () ++{ ++static struct elf_prstatus32 ac_aggr; ++if (sizeof ac_aggr.pr_reg) ++return 0; ++ ; ++ return 0; ++} ++_ACEOF ++rm -f conftest.$ac_objext ++if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ++ (eval $ac_compile) 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } && ++ { ac_try='test -z "$ac_c_werror_flag" ++ || test ! -s conftest.err' ++ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 ++ (eval $ac_try) 2>&5 ++ ac_status=$? ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); }; } && ++ { ac_try='test -s conftest.$ac_objext' ++ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 ++ (eval $ac_try) 2>&5 ++ ac_status=$? ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); }; }; then ++ ac_cv_member_struct_elf_prstatus32_pr_reg=yes ++else ++ echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ac_cv_member_struct_elf_prstatus32_pr_reg=no ++fi ++rm -f conftest.err conftest.$ac_objext conftest.$ac_ext ++fi ++rm -f conftest.err conftest.$ac_objext conftest.$ac_ext ++fi ++echo "$as_me:$LINENO: result: $ac_cv_member_struct_elf_prstatus32_pr_reg" >&5 ++echo "${ECHO_T}$ac_cv_member_struct_elf_prstatus32_pr_reg" >&6 ++if test $ac_cv_member_struct_elf_prstatus32_pr_reg = yes; then ++ ++cat >>confdefs.h <<\_ACEOF ++#define HAVE_ELF_PRSTATUS32 1 ++_ACEOF ++ ++fi ++ + # elf_hp.h is for HP/UX 64-bit shared library support. + # FIXME: kettenis/20030102: In most cases we include these (ctype.h, time.h) + # unconditionally, so what's the point in checking these? +Index: gdb-6.8.50.20081214/gdb/configure.ac +=================================================================== +--- gdb-6.8.50.20081214.orig/gdb/configure.ac 2008-12-14 21:17:01.000000000 +0100 ++++ gdb-6.8.50.20081214/gdb/configure.ac 2008-12-14 21:32:35.000000000 +0100 +@@ -686,6 +686,11 @@ AC_SUBST(PYTHON_CFLAGS) + AC_HEADER_DIRENT + AC_HEADER_STAT + AC_HEADER_STDC ++AC_CHECK_HEADERS([sys/user32.h sys/procfs32.h]) ++AC_CHECK_MEMBER([struct elf_prstatus32.pr_reg], ++ [AC_DEFINE(HAVE_ELF_PRSTATUS32, 1, ++ [Define if struct elf_prstatus32 is available. ])], ++ [], [#include ]) + # elf_hp.h is for HP/UX 64-bit shared library support. + # FIXME: kettenis/20030102: In most cases we include these (ctype.h, time.h) + # unconditionally, so what's the point in checking these? +Index: gdb-6.8.50.20081214/gdb/gcore.c +=================================================================== +--- gdb-6.8.50.20081214.orig/gdb/gcore.c 2008-12-14 21:17:01.000000000 +0100 ++++ gdb-6.8.50.20081214/gdb/gcore.c 2008-12-14 21:17:10.000000000 +0100 +@@ -320,6 +320,11 @@ gcore_create_callback (CORE_ADDR vaddr, + asection *osec; + flagword flags = SEC_ALLOC | SEC_HAS_CONTENTS | SEC_LOAD; + ++ /* Some Linux kernel versions around 2.6.17 have for i386 inferiors running ++ in compatibility mode on amd64 kernel their VSYSCALL page (at 0xffffe000) ++ protected as RWX==000 by default and gdb fails to read the library header ++ upon loading the core. This is a Linux kernel bug being fixed. */ ++ + /* If the memory segment has no permissions set, ignore it, otherwise + when we later try to access it for read/write, we'll get an error + or jam the kernel. */ +Index: gdb-6.8.50.20081214/gdb/gdb_procfs32.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8.50.20081214/gdb/gdb_procfs32.h 2008-12-14 21:32:56.000000000 +0100 +@@ -0,0 +1,128 @@ ++#ifdef HAVE_SYS_PROCFS32_H ++#include ++#elif !defined HAVE_ELF_PRSTATUS32 ++ ++/* Copyright (C) 2006 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, write to the Free ++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ 02111-1307 USA. */ ++ ++#ifndef _SYS_PROCFS32_H ++#define _SYS_PROCFS32_H 1 ++ ++/* This is somewhat modelled after the file of the same name on SVR4 ++ systems. It provides a definition of the core file format for ELF ++ used on Linux. It doesn't have anything to do with the /proc file ++ system, even though Linux has one. ++ ++ Anyway, the whole purpose of this file is for GDB and GDB only. ++ Don't read too much into it. Don't use it for anything other than ++ GDB unless you know what you are doing. */ ++ ++#include ++#include ++#include ++#include "gdb_user32.h" ++ ++/* We define here only the symbols differing from their 64-bit variant. */ ++#include ++ ++__BEGIN_DECLS ++ ++/* Type for a general-purpose register. */ ++typedef unsigned int elf_greg32_t; ++ ++/* And the whole bunch of them. We could have used `struct ++ user_regs_struct' directly in the typedef, but tradition says that ++ the register set is an array, which does have some peculiar ++ semantics, so leave it that way. */ ++#define ELF_NGREG32 (sizeof (struct user_regs32_struct) / sizeof(elf_greg32_t)) ++typedef elf_greg32_t elf_gregset32_t[ELF_NGREG32]; ++ ++/* Register set for the floating-point registers. */ ++typedef struct user_fpregs32_struct elf_fpregset32_t; ++ ++/* Register set for the extended floating-point registers. Includes ++ the Pentium III SSE registers in addition to the classic ++ floating-point stuff. */ ++typedef struct user_fpxregs32_struct elf_fpxregset32_t; ++ ++ ++/* Definitions to generate Intel SVR4-like core files. These mostly ++ have the same names as the SVR4 types with "elf_" tacked on the ++ front to prevent clashes with Linux definitions, and the typedef ++ forms have been avoided. This is mostly like the SVR4 structure, ++ but more Linuxy, with things that Linux does not support and which ++ GDB doesn't really use excluded. */ ++ ++struct prstatus32_timeval ++ { ++ int tv_sec; ++ int tv_usec; ++ }; ++ ++struct elf_prstatus32 ++ { ++ struct elf_siginfo pr_info; /* Info associated with signal. */ ++ short int pr_cursig; /* Current signal. */ ++ unsigned int pr_sigpend; /* Set of pending signals. */ ++ unsigned int pr_sighold; /* Set of held signals. */ ++ __pid_t pr_pid; ++ __pid_t pr_ppid; ++ __pid_t pr_pgrp; ++ __pid_t pr_sid; ++ struct prstatus32_timeval pr_utime; /* User time. */ ++ struct prstatus32_timeval pr_stime; /* System time. */ ++ struct prstatus32_timeval pr_cutime; /* Cumulative user time. */ ++ struct prstatus32_timeval pr_cstime; /* Cumulative system time. */ ++ elf_gregset32_t pr_reg; /* GP registers. */ ++ int pr_fpvalid; /* True if math copro being used. */ ++ }; ++ ++ ++struct elf_prpsinfo32 ++ { ++ char pr_state; /* Numeric process state. */ ++ char pr_sname; /* Char for pr_state. */ ++ char pr_zomb; /* Zombie. */ ++ char pr_nice; /* Nice val. */ ++ unsigned int pr_flag; /* Flags. */ ++ unsigned short int pr_uid; ++ unsigned short int pr_gid; ++ int pr_pid, pr_ppid, pr_pgrp, pr_sid; ++ /* Lots missing */ ++ char pr_fname[16]; /* Filename of executable. */ ++ char pr_psargs[ELF_PRARGSZ]; /* Initial part of arg list. */ ++ }; ++ ++ ++/* The rest of this file provides the types for emulation of the ++ Solaris interfaces that should be implemented by ++ users of libthread_db. */ ++ ++/* Register sets. Linux has different names. */ ++typedef elf_gregset_t prgregset32_t; ++typedef elf_fpregset_t prfpregset32_t; ++ ++/* Process status and info. In the end we do provide typedefs for them. */ ++typedef struct elf_prstatus32 prstatus32_t; ++typedef struct elf_prpsinfo32 prpsinfo32_t; ++ ++__END_DECLS ++ ++#endif /* _SYS_PROCFS32_H */ ++ ++#endif /* HAVE_SYS_PROCFS32_H */ +Index: gdb-6.8.50.20081214/gdb/gdb_user32.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8.50.20081214/gdb/gdb_user32.h 2008-12-14 21:17:10.000000000 +0100 +@@ -0,0 +1,108 @@ ++#ifdef HAVE_SYS_USER32_H ++#include ++#else ++ ++#ifdef HAVE_STDINT_H ++#include ++typedef int32_t gdb_int32_t; ++typedef uint32_t gdb_uint32_t; ++#else ++typedef signed int gdb_uint32_t; ++typedef unsigned int gdb_uint32_t; ++#endif ++ ++/* Copyright (C) 2006 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, write to the Free ++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ 02111-1307 USA. */ ++ ++#ifndef _SYS_USER32_H ++#define _SYS_USER32_H 1 ++ ++/* These are the 32-bit x86 structures. */ ++ ++struct user_fpregs32_struct ++{ ++ int32_t cwd; ++ int32_t swd; ++ int32_t twd; ++ int32_t fip; ++ int32_t fcs; ++ int32_t foo; ++ int32_t fos; ++ int32_t st_space [20]; ++}; ++ ++struct user_fpxregs32_struct ++{ ++ unsigned short int cwd; ++ unsigned short int swd; ++ unsigned short int twd; ++ unsigned short int fop; ++ int32_t fip; ++ int32_t fcs; ++ int32_t foo; ++ int32_t fos; ++ int32_t mxcsr; ++ int32_t reserved; ++ int32_t st_space[32]; /* 8*16 bytes for each FP-reg = 128 bytes */ ++ int32_t xmm_space[32]; /* 8*16 bytes for each XMM-reg = 128 bytes */ ++ int32_t padding[56]; ++}; ++ ++struct user_regs32_struct ++{ ++ int32_t ebx; ++ int32_t ecx; ++ int32_t edx; ++ int32_t esi; ++ int32_t edi; ++ int32_t ebp; ++ int32_t eax; ++ int32_t xds; ++ int32_t xes; ++ int32_t xfs; ++ int32_t xgs; ++ int32_t orig_eax; ++ int32_t eip; ++ int32_t xcs; ++ int32_t eflags; ++ int32_t esp; ++ int32_t xss; ++}; ++ ++struct user32 ++{ ++ struct user_regs32_struct regs; ++ int u_fpvalid; ++ struct user_fpregs32_struct i387; ++ uint32_t u_tsize; ++ uint32_t u_dsize; ++ uint32_t u_ssize; ++ uint32_t start_code; ++ uint32_t start_stack; ++ int32_t signal; ++ int reserved; ++ struct user_regs32_struct* u_ar0; ++ struct user_fpregs32_struct* u_fpstate; ++ uint32_t magic; ++ char u_comm [32]; ++ int u_debugreg [8]; ++}; ++ ++#endif /* _SYS_USER32_H */ ++ ++#endif /* HAVE_SYS_USER32_H */ +Index: gdb-6.8.50.20081214/gdb/linux-nat.c +=================================================================== +--- gdb-6.8.50.20081214.orig/gdb/linux-nat.c 2008-12-14 21:17:01.000000000 +0100 ++++ gdb-6.8.50.20081214/gdb/linux-nat.c 2008-12-14 21:24:20.000000000 +0100 +@@ -213,6 +213,21 @@ static LONGEST (*super_xfer_partial) (st + const gdb_byte *, + ULONGEST, LONGEST); + ++/* This functions make elfcore note sections. ++ They may get overriden by code adjusting data for multi-target builds. */ ++char *(*linux_elfcore_write_prpsinfo) ++ (bfd *, char *, int *, const char *, const char *) = elfcore_write_prpsinfo; ++char *(*linux_elfcore_write_prstatus) ++ (bfd *, char *, int *, long, int, const void *) = elfcore_write_prstatus; ++static char * ++linux_elfcore_write_prfpreg_bfd (bfd *abfd, char *buf, int *bufsiz, ++ const void *fpregs, int size, struct regcache *regcache) ++{ ++ return elfcore_write_prfpreg (abfd, buf, bufsiz, fpregs, size); ++} ++char *(*linux_elfcore_write_prfpreg) (bfd *, char *, int *, const void *, int, ++ struct regcache *) = linux_elfcore_write_prfpreg_bfd; ++ + static int debug_linux_nat; + static void + show_debug_linux_nat (struct ui_file *file, int from_tty, +@@ -3473,7 +3488,7 @@ linux_nat_do_thread_registers (bfd *obfd + else + fill_gregset (regcache, &gregs, -1); + +- note_data = (char *) elfcore_write_prstatus (obfd, ++ note_data = (char *) linux_elfcore_write_prstatus (obfd, + note_data, + note_size, + lwp, +@@ -3523,10 +3538,10 @@ linux_nat_do_thread_registers (bfd *obfd + else + fill_fpregset (regcache, &fpregs, -1); + +- note_data = (char *) elfcore_write_prfpreg (obfd, ++ note_data = (char *) linux_elfcore_write_prfpreg (obfd, + note_data, + note_size, +- &fpregs, sizeof (fpregs)); ++ &fpregs, sizeof (fpregs), regcache); + } + + return note_data; +@@ -3595,9 +3610,9 @@ linux_nat_make_corefile_notes (bfd *obfd + psargs_end - string_end); + } + } +- note_data = (char *) elfcore_write_prpsinfo (obfd, +- note_data, +- note_size, fname, psargs); ++ note_data = (char *) linux_elfcore_write_prpsinfo (obfd, note_data, ++ note_size, fname, ++ psargs); + } + + /* Dump information for threads. */ +Index: gdb-6.8.50.20081214/gdb/linux-nat.h +=================================================================== +--- gdb-6.8.50.20081214.orig/gdb/linux-nat.h 2008-12-14 21:17:01.000000000 +0100 ++++ gdb-6.8.50.20081214/gdb/linux-nat.h 2008-12-14 21:24:11.000000000 +0100 +@@ -134,3 +134,12 @@ void linux_nat_switch_fork (ptid_t new_p + + /* Return the saved siginfo associated with PTID. */ + struct siginfo *linux_nat_get_siginfo (ptid_t ptid); ++ ++/* These functions make elfcore note sections. ++ They may get overriden by code adjusting data for multi-target builds. */ ++extern char *(*linux_elfcore_write_prpsinfo) ++ (bfd *, char *, int *, const char *, const char *); ++extern char *(*linux_elfcore_write_prstatus) ++ (bfd *, char *, int *, long, int, const void *); ++extern char *(*linux_elfcore_write_prfpreg) ++ (bfd *, char *, int *, const void *, int, struct regcache *); diff --git a/gdb-6.5-ia64-libunwind-leak-test.patch b/gdb-6.5-ia64-libunwind-leak-test.patch new file mode 100644 index 0000000..79a4753 --- /dev/null +++ b/gdb-6.5-ia64-libunwind-leak-test.patch @@ -0,0 +1,127 @@ +diff -u -rup gdb-6.3-orig/gdb/testsuite/gdb.base/unwind-leak.c gdb-6.3/gdb/testsuite/gdb.base/unwind-leak.c +--- gdb-6.3-orig/gdb/testsuite/gdb.base/unwind-leak.c 2007-12-19 15:12:55.000000000 -0500 ++++ gdb-6.3/gdb/testsuite/gdb.base/unwind-leak.c 2007-12-19 13:55:22.000000000 -0500 +@@ -0,0 +1,29 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2007 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++ Please email any bugs, comments, and/or additions to this file to: ++ bug-gdb@prep.ai.mit.edu */ ++ ++#include ++ ++int main() ++{ ++ for (;;) ++ alarm (0); ++ return 0; ++} +diff -u -rup gdb-6.3-orig/gdb/testsuite/gdb.base/unwind-leak.exp gdb-6.3/gdb/testsuite/gdb.base/unwind-leak.exp +--- gdb-6.3-orig/gdb/testsuite/gdb.base/unwind-leak.exp 2007-12-19 15:12:53.000000000 -0500 ++++ gdb-6.3/gdb/testsuite/gdb.base/unwind-leak.exp 2007-12-19 15:11:35.000000000 -0500 +@@ -0,0 +1,90 @@ ++# Copyright 2007 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++if $tracelevel then { ++ strace $tracelevel ++} ++ ++set prms_id 0 ++set bug_id 0 ++ ++set testfile unwind-leak ++set srcfile ${testfile}.c ++set shfile ${objdir}/${subdir}/${testfile}-gdb.sh ++set binfile ${objdir}/${subdir}/${testfile} ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { ++ untested "Couldn't compile test program" ++ return -1 ++} ++ ++# Get things started. ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++set pid [exp_pid -i [board_info host fileid]] ++ ++# For C programs, "start" should stop in main(). ++ ++gdb_test "start" \ ++ "main \\(\\) at .*$srcfile.*" \ ++ "start" ++ ++set loc [gdb_get_line_number "alarm"] ++gdb_breakpoint $loc ++ ++proc memory_get {} { ++ global pid ++ set fd [open "/proc/$pid/statm"] ++ gets $fd line ++ close $fd ++ # number of pages of data/stack ++ scan $line "%*d%*d%*d%*d%*d%d" drs ++ return $drs ++} ++ ++set cycles 100 ++# For 100 cycles it was 1308: from = 363 KB, to = 1671 KB ++set permit_kb 100 ++verbose -log "cycles = $cycles, permit_kb = $permit_kb" ++ ++set fail 0 ++set test "breakpoint stop/continue cycles" ++for {set i $cycles} {$i > 0} {set i [expr {$i - 1}]} { ++ gdb_test_multiple "continue" $test { ++ -re "Breakpoint 2, main .*alarm .*.*${gdb_prompt} $" { ++ } ++ -re "Segmentation fault" { ++ fail $test ++ set i 0 ++ set fail 1 ++ } ++ } ++ if ![info exists from] { ++ set from [memory_get] ++ } ++} ++set to [memory_get] ++if {!$fail} { ++ verbose -log "from = $from KB, to = $to KB" ++ if {$from > 0 && $to > 10 && $to < $from + $permit_kb} { ++ pass $test ++ } else { ++ fail $test ++ } ++} diff --git a/gdb-6.5-last-address-space-byte-test.patch b/gdb-6.5-last-address-space-byte-test.patch new file mode 100644 index 0000000..8bdbb2b --- /dev/null +++ b/gdb-6.5-last-address-space-byte-test.patch @@ -0,0 +1,56 @@ +Index: ./gdb/testsuite/gdb.base/largecore-last-address-lock.exp +=================================================================== +RCS file: ./gdb/testsuite/gdb.base/largecore-last-address-lock.exp +diff -N ./gdb/testsuite/gdb.base/largecore-last-address-lock.exp +--- /dev/null 1 Jan 1970 00:00:00 -0000 ++++ ./gdb/testsuite/gdb.base/largecore-last-address-lock.exp 15 Nov 2006 21:43:24 -0000 +@@ -0,0 +1,49 @@ ++# Copyright 2006 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++if $tracelevel then { ++ strace $tracelevel ++} ++ ++# Get things started. ++ ++gdb_exit ++gdb_start ++ ++# i386 (32-bit) only: gdb with Red Hat largecore patch did lock up: ++# https://enterprise.redhat.com/issue-tracker/?module=issues&action=view&tid=103263 ++# https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=210614 ++ ++# i386: Bug exists when the `target_xfer_memory' condition ++# `(memaddr + len < region->hi)' operates on 64-bit operands on ++# largecore-patched with 32-bit addresses and so it can get `false' with ++# arbitrary `len'. ++ ++# x86_64: The bug is not present as the operands and calculations have the same ++# bit size. Would would still need to pass there the highest address ++# (`memaddr == 0xffffffffffffffff') but we would need to pass `len == 0' ++# to make the condition `(memaddr + len < region->hi)' false. ++# `len == 0' would get caught eariler. ++ ++# Error in the success case is immediate. ++set timeoutold ${timeout} ++set timeout 10 ++ ++gdb_test "x/xb 0xffffffff" \ ++ "Cannot access memory at address 0xffffffff" \ ++ "Read the last address space byte" ++ ++set timeout ${timeoutold} diff --git a/gdb-6.5-missed-trap-on-step-test.patch b/gdb-6.5-missed-trap-on-step-test.patch new file mode 100644 index 0000000..cb55193 --- /dev/null +++ b/gdb-6.5-missed-trap-on-step-test.patch @@ -0,0 +1,90 @@ +Fix has been committed to: + gdb-6.6-scheduler_locking-step-sw-watchpoints2.patch + +--- /dev/null 2007-12-14 20:45:09.113039517 +0100 ++++ gdb-6.5/gdb/testsuite/gdb.base/watchpoint-during-step.exp 2007-12-24 19:42:00.000000000 +0100 +@@ -0,0 +1,51 @@ ++# Copyright 2007 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++if $tracelevel then { ++ strace $tracelevel ++} ++ ++set prms_id 0 ++set bug_id 0 ++ ++set testfile watchpoint-during-step ++set srcfile ${testfile}.c ++set binfile ${objdir}/${subdir}/${testfile} ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { ++ untested "Couldn't compile test program" ++ return -1 ++} ++ ++# Get things started. ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++runto_main ++ ++gdb_breakpoint [gdb_get_line_number "var = 2"] ++gdb_continue_to_breakpoint "Find the first var set" ++ ++gdb_test "step" ".*var = 3;" "Step to the next var set" ++ ++gdb_test "watch var" "atchpoint .*: var" "Set the watchpoint" ++ ++# Here is the target point. Be careful to not have breakpoint set on the line ++# we step from as in this case it is a valid upstream KFAIL gdb/38 ++ ++gdb_test "step" ".*Old value = 2.*New value = 3.*" "Catch the watchpoint" +--- /dev/null 2007-12-14 20:45:09.113039517 +0100 ++++ gdb-6.5/gdb/testsuite/gdb.base/watchpoint-during-step.c 2007-12-24 19:38:10.000000000 +0100 +@@ -0,0 +1,30 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2007 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++ Please email any bugs, comments, and/or additions to this file to: ++ bug-gdb@prep.ai.mit.edu */ ++ ++static int var; ++ ++int main() ++{ ++ var = 1; ++ var = 2; ++ var = 3; ++ return 0; ++} diff --git a/gdb-6.5-readline-long-line-crash-test.patch b/gdb-6.5-readline-long-line-crash-test.patch new file mode 100644 index 0000000..86a82a4 --- /dev/null +++ b/gdb-6.5-readline-long-line-crash-test.patch @@ -0,0 +1,136 @@ +https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=214196 + + +Index: ./gdb/testsuite/gdb.base/readline-overflow.exp +=================================================================== +RCS file: ./gdb/testsuite/gdb.base/readline-overflow.exp +diff -N ./gdb/testsuite/gdb.base/readline-overflow.exp +--- /dev/null 1 Jan 1970 00:00:00 -0000 ++++ ./gdb/testsuite/gdb.base/readline-overflow.exp 13 Nov 2006 23:42:50 -0000 +@@ -0,0 +1,125 @@ ++# Copyright 2006 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++# Please email any bugs, comments, and/or additions to this file to: ++# bug-gdb@prep.ai.mit.edu ++ ++# This file was written by Jan Kratochvil ++ ++# This file is part of the gdb testsuite. ++ ++# ++# Tests for readline buffer overflow. ++# ++ ++if $tracelevel { ++ strace $tracelevel ++} ++ ++# Don't let a .inputrc file or an existing setting of INPUTRC mess up ++# the test results. Even if /dev/null doesn't exist on the particular ++# platform, the readline library will use the default setting just by ++# failing to open the file. OTOH, opening /dev/null successfully will ++# also result in the default settings being used since nothing will be ++# read from this file. ++global env ++if [info exists env(INPUTRC)] { ++ set old_inputrc $env(INPUTRC) ++} ++set env(INPUTRC) "/dev/null" ++ ++set oldtimeout1 $timeout ++set timeout 600 ++ ++if [info exists env(GDBHISTFILE)] { ++ set old_gdbhistfile $env(GDBHISTFILE) ++} ++if [info exists env(HISTSIZE)] { ++ set old_histsize $env(HISTSIZE) ++} ++set env(GDBHISTFILE) "${srcdir}/${subdir}/gdb_history" ++set env(HISTSIZE) "10" ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++ ++ ++set width 11 ++gdb_test "set width $width" \ ++ "" \ ++ "Setting width to $width." ++#gdb_test "set height 1" \ ++# "" \ ++# "Setting height to 1." ++send_gdb "run X" ++set i 0 ++# It crashes using `set width 7' on `set total 3560'. ++# Sometimes it corrupts screen on `set width 7'. ++# Bugreport used `set total 130001': ++# https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=214196 ++# Check also `timeout' above. ++set total 4200 ++gdb_expect { ++ -re X { ++ incr i ++ if {$i <= $total} { ++ send_gdb "X" ++ exp_continue ++ } ++ } ++ -re "\[ \b\r\n\]" { ++ exp_continue ++ } ++ eof { ++ fail "gdb sending total $total characters" ++ note "Failed after sending $i characters, reason: EOF" ++ gdb_clear_suppressed ++ } ++ timeout { ++ fail "gdb sending total $total characters" ++ note "Failed after sending $i characters (timeout $timeout), reason: TIMEOUT" ++ gdb_clear_suppressed ++ } ++ default { ++ fail "gdb sending total $total characters" ++ note "Failed after sending $i characters, reason: 0=\[$expect_out(0,string)\] buffer=\[$expect_out(buffer)\]" ++ gdb_clear_suppressed ++ } ++} ++gdb_test "\r" \ ++ "No executable file specified..*" \ ++ "All the characters transferred" ++ ++ ++# Restore globals modified in this test... ++if [info exists old_inputrc] { ++ set env(INPUTRC) $old_inputrc ++} else { ++ unset env(INPUTRC) ++} ++if [info exists old_gdbhistfile] { ++ set env(GDBHISTFILE) $old_gdbhistfile ++} else { ++ unset env(GDBHISTFILE) ++} ++if [info exists old_histsize] { ++ set env(HISTSIZE) $old_histsize ++} else { ++ unset env(HISTSIZE) ++} ++set timeout $oldtimeout1 ++ ++return 0 diff --git a/gdb-6.5-readline-long-line-crash.patch b/gdb-6.5-readline-long-line-crash.patch new file mode 100644 index 0000000..cc76179 --- /dev/null +++ b/gdb-6.5-readline-long-line-crash.patch @@ -0,0 +1,165 @@ +Fix Valgrind paste of >= 256 * (screen width) characters (as 130001). + +Invalid write of size 4 + at 0x8203BD9: rl_redisplay (display.c:812) + by 0x81F5130: _rl_internal_char_cleanup (readline.c:427) + by 0x81F52B3: readline_internal_char (readline.c:508) + by 0x8209817: rl_callback_read_char (callback.c:184) + by 0x8135312: rl_callback_read_char_wrapper (event-top.c:179) + by 0x8135B7B: stdin_event_handler (event-top.c:432) + by 0x81349F2: handle_file_event (event-loop.c:730) + by 0x81342AB: process_event (event-loop.c:343) + by 0x81342F4: gdb_do_one_event (event-loop.c:380) + by 0x81313AC: catch_errors (exceptions.c:515) + by 0x80CE8CA: tui_command_loop (tui-interp.c:151) + by 0x81318B9: current_interp_command_loop (interps.c:278) + Address 0x43DCEB8 is 0 bytes after a block of size 1,024 alloc'd + at 0x4005400: malloc (vg_replace_malloc.c:149) + by 0x8087084: xmalloc (utils.c:959) + by 0x8202CA7: init_line_structures (display.c:440) + by 0x8202D14: rl_redisplay (display.c:471) + by 0x81F4F53: readline_internal_setup (readline.c:363) + by 0x820958C: _rl_callback_newline (callback.c:89) + by 0x82095BB: rl_callback_handler_install (callback.c:101) + by 0x80CE896: tui_command_loop (tui-interp.c:138) + by 0x81318B9: current_interp_command_loop (interps.c:278) + by 0x807E69A: captured_command_loop (main.c:101) + by 0x81313AC: catch_errors (exceptions.c:515) + by 0x807F55A: captured_main (main.c:826) + + +2006-11-08 Jan Kratochvil + + * readline/display.c (line_state, line_state_array, line_state_visible, + line_state_invisible): Encapsulate _rl_wrapped_line, inv_lbreaks, + inv_lbsize, vis_lbreaks, vis_lbsize, visible_line, invisible_line. + (init_line_structures): Initialize both _rl_wrapped_line ones now. + (rl_redisplay): Fix _rl_wrapped_line handling by using its own size. + Swap whole `line_state_visible' / `line_state_invisible' structures. + (update_line): Update for new `_rl_wrapped_line'. + + +Index: ./readline/display.c +=================================================================== +--- ./readline/display.c 5 May 2006 18:26:12 -0000 1.11 ++++ ./readline/display.c 8 Nov 2006 18:23:33 -0000 +@@ -73,15 +73,31 @@ static void delete_chars PARAMS((int)); + static void insert_some_chars PARAMS((char *, int, int)); + static void cr PARAMS((void)); + ++struct line_state ++ { ++ char *line; ++ int *lbreaks; ++ int lbreaks_size; ++#if defined (HANDLE_MULTIBYTE) ++ int *wrapped_line; ++ int wrapped_line_size; ++#endif ++ }; ++static struct line_state line_state_array[2]; ++static struct line_state *line_state_visible = &line_state_array[0]; ++static struct line_state *line_state_invisible = &line_state_array[1]; ++ + #if defined (HANDLE_MULTIBYTE) + static int _rl_col_width PARAMS((const char *, int, int)); +-static int *_rl_wrapped_line; + #else + # define _rl_col_width(l, s, e) (((e) <= (s)) ? 0 : (e) - (s)) + #endif + +-static int *inv_lbreaks, *vis_lbreaks; +-static int inv_lbsize, vis_lbsize; ++/* FIXME: Backward compatible naming. */ ++#define inv_lbreaks (line_state_invisible->lbreaks) ++#define inv_lbsize (line_state_invisible->lbreaks_size) ++#define vis_lbreaks (line_state_visible->lbreaks) ++#define vis_lbsize (line_state_visible->lbreaks_size) + + /* Heuristic used to decide whether it is faster to move from CUR to NEW + by backing up or outputting a carriage return and moving forward. */ +@@ -150,8 +166,9 @@ static int last_lmargin; + + /* The line display buffers. One is the line currently displayed on + the screen. The other is the line about to be displayed. */ +-static char *visible_line = (char *)NULL; +-static char *invisible_line = (char *)NULL; ++/* FIXME: Backward compatible naming. */ ++#define visible_line (line_state_visible->line) ++#define invisible_line (line_state_invisible->line) + + /* A buffer for `modeline' messages. */ + static char msg_buf[128]; +@@ -437,7 +454,10 @@ init_line_structures (minsize) + inv_lbreaks = (int *)xmalloc (inv_lbsize * sizeof (int)); + vis_lbreaks = (int *)xmalloc (vis_lbsize * sizeof (int)); + #if defined (HANDLE_MULTIBYTE) +- _rl_wrapped_line = (int *)xmalloc (vis_lbsize * sizeof (int)); ++ line_state_visible->wrapped_line_size = vis_lbsize; ++ line_state_visible->wrapped_line = (int *)xmalloc (line_state_visible->wrapped_line_size * sizeof (int)); ++ line_state_invisible->wrapped_line_size = inv_lbsize; ++ line_state_invisible->wrapped_line = (int *)xmalloc (line_state_invisible->wrapped_line_size * sizeof (int)); + #endif + inv_lbreaks[0] = vis_lbreaks[0] = 0; + } +@@ -572,10 +592,15 @@ rl_redisplay () + { \ + inv_lbsize *= 2; \ + inv_lbreaks = (int *)xrealloc (inv_lbreaks, inv_lbsize * sizeof (int)); \ +- _rl_wrapped_line = (int *)xrealloc (_rl_wrapped_line, inv_lbsize * sizeof (int)); \ + } \ + inv_lbreaks[++newlines] = out; \ +- _rl_wrapped_line[newlines] = _rl_wrapped_multicolumn; \ ++ if (newlines >= (line_state_invisible->wrapped_line_size - 1)) \ ++ { \ ++ line_state_invisible->wrapped_line_size *= 2; \ ++ line_state_invisible->wrapped_line = (int *)xrealloc (line_state_invisible->wrapped_line, \ ++ line_state_invisible->wrapped_line_size * sizeof (int)); \ ++ } \ ++ line_state_invisible->wrapped_line[newlines] = _rl_wrapped_multicolumn; \ + lpos = 0; \ + } \ + } while (0) +@@ -605,7 +630,7 @@ rl_redisplay () + #endif + + #if defined (HANDLE_MULTIBYTE) +- memset (_rl_wrapped_line, 0, vis_lbsize); ++ memset (line_state_invisible->wrapped_line, 0, line_state_invisible->wrapped_line_size * sizeof (int)); + num = 0; + #endif + +@@ -1118,17 +1143,10 @@ rl_redisplay () + + /* Swap visible and non-visible lines. */ + { +- char *vtemp = visible_line; +- int *itemp = vis_lbreaks, ntemp = vis_lbsize; +- +- visible_line = invisible_line; +- invisible_line = vtemp; +- +- vis_lbreaks = inv_lbreaks; +- inv_lbreaks = itemp; +- +- vis_lbsize = inv_lbsize; +- inv_lbsize = ntemp; ++ struct line_state *line_state_temp = line_state_visible; ++ ++ line_state_visible = line_state_invisible; ++ line_state_invisible = line_state_temp; + + rl_display_fixed = 0; + /* If we are displaying on a single line, and last_lmargin is > 0, we +@@ -1194,8 +1212,9 @@ update_line (old, new, current_line, oma + /* This fixes only double-column characters, but if the wrapped + character comsumes more than three columns, spaces will be + inserted in the string buffer. */ +- if (_rl_wrapped_line[current_line] > 0) +- _rl_clear_to_eol (_rl_wrapped_line[current_line]); ++ if (current_line < line_state_visible->wrapped_line_size ++ && line_state_visible->wrapped_line[current_line] > 0) ++ _rl_clear_to_eol (line_state_visible->wrapped_line[current_line]); + + memset (&ps, 0, sizeof (mbstate_t)); + ret = mbrtowc (&wc, new, MB_CUR_MAX, &ps); diff --git a/gdb-6.5-section-num-fixup-test.patch b/gdb-6.5-section-num-fixup-test.patch new file mode 100644 index 0000000..53f7fec --- /dev/null +++ b/gdb-6.5-section-num-fixup-test.patch @@ -0,0 +1,111 @@ +diff -up -ruNp gdb-6.5-orig/gdb/testsuite/gdb.base/datalib-lib.c gdb-6.5/gdb/testsuite/gdb.base/datalib-lib.c +--- gdb-6.5-orig/gdb/testsuite/gdb.base/datalib-lib.c 1969-12-31 19:00:00.000000000 -0500 ++++ gdb-6.5/gdb/testsuite/gdb.base/datalib-lib.c 2008-05-29 13:51:50.000000000 -0400 +@@ -0,0 +1,22 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2008 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++ Please email any bugs, comments, and/or additions to this file to: ++ bug-gdb@prep.ai.mit.edu */ ++ ++int var; +diff -up -ruNp gdb-6.5-orig/gdb/testsuite/gdb.base/datalib-main.c gdb-6.5/gdb/testsuite/gdb.base/datalib-main.c +--- gdb-6.5-orig/gdb/testsuite/gdb.base/datalib-main.c 1969-12-31 19:00:00.000000000 -0500 ++++ gdb-6.5/gdb/testsuite/gdb.base/datalib-main.c 2008-05-29 13:51:39.000000000 -0400 +@@ -0,0 +1,26 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2008 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++ Please email any bugs, comments, and/or additions to this file to: ++ bug-gdb@prep.ai.mit.edu */ ++ ++int ++main (void) ++{ ++ return 0; ++} +diff -up -ruNp gdb-6.5-orig/gdb/testsuite/gdb.base/datalib.exp gdb-6.5/gdb/testsuite/gdb.base/datalib.exp +--- gdb-6.5-orig/gdb/testsuite/gdb.base/datalib.exp 1969-12-31 19:00:00.000000000 -0500 ++++ gdb-6.5/gdb/testsuite/gdb.base/datalib.exp 2008-05-29 14:58:33.000000000 -0400 +@@ -0,0 +1,51 @@ ++# Copyright 2008 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++set testfile datalib ++set srcfilemain ${testfile}-main.c ++set srcfilelib ${testfile}-lib.c ++set libfile ${objdir}/${subdir}/${testfile}-lib.so ++set binfile ${objdir}/${subdir}/${testfile}-main ++if { [gdb_compile "${srcdir}/${subdir}/${srcfilelib}" "${libfile}" executable [list debug {additional_flags=-shared -nostdlib}]] != "" } { ++ untested "Couldn't compile test program" ++ return -1 ++} ++if { [gdb_compile "${srcdir}/${subdir}/${srcfilemain}" "${binfile} ${libfile}" executable {debug}] != "" } { ++ untested "Couldn't compile test program" ++ return -1 ++} ++ ++# Get things started. ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++# We must use a separate library as the main executable is compiled to the ++# address 0 by default and it would get fixed up already at the end of ++# INIT_OBJFILE_SECT_INDICES. We also cannot PRELINK it as PRELINK is missing ++# on ia64. The library must be NOSTDLIB as otherwise some stub code would ++# create the `.text' section there. Also DEBUG option is useful as some of ++# the crashes occur in dwarf2read.c. ++ ++# FAIL case: ++# ../../gdb/ia64-tdep.c:2838: internal-error: sect_index_text not initialized ++# A problem internal to GDB has been detected, ++ ++gdb_test "start" \ ++ "main \\(\\) at .*${srcfilemain}.*" \ ++ "start" diff --git a/gdb-6.5-sharedlibrary-path.patch b/gdb-6.5-sharedlibrary-path.patch new file mode 100644 index 0000000..3e0c101 --- /dev/null +++ b/gdb-6.5-sharedlibrary-path.patch @@ -0,0 +1,171 @@ +If you provided some relative path to the shared library, such as with + export LD_LIBRARY_PATH=. +then gdb would fail to match the shared library name during the TLS lookup. + + +Dropped the workaround/fix for gdb-6.8.50.20081128 - is it still needed? + + +The testsuite needs `gdb-6.3-bz146810-solib_absolute_prefix_is_empty.patch'. +The testsuite needs `gdb-6.5-tls-of-separate-debuginfo.patch'. + + +2006-09-01 Jan Kratochvil + + * solib-svr4.c (svr4_fetch_objfile_link_map): Match even absolute + requested pathnames to the internal loaded relative pathnames. + +2007-10-16 Jan Kratochvil + + Port to GDB-6.7. + +2008-02-27 Jan Kratochvil + + Port to gdb-6.7.50.20080227. + +Index: gdb-6.7.50.20080227/gdb/testsuite/gdb.threads/tls-sepdebug-main.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.7.50.20080227/gdb/testsuite/gdb.threads/tls-sepdebug-main.c 2008-02-27 09:00:15.000000000 +0100 +@@ -0,0 +1,25 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2006 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++ Please email any bugs, comments, and/or additions to this file to: ++ bug-gdb@prep.ai.mit.edu */ ++ ++int main() ++{ ++ return 0; ++} +Index: gdb-6.7.50.20080227/gdb/testsuite/gdb.threads/tls-sepdebug-shared.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.7.50.20080227/gdb/testsuite/gdb.threads/tls-sepdebug-shared.c 2008-02-27 09:00:15.000000000 +0100 +@@ -0,0 +1,22 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2006 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++ Please email any bugs, comments, and/or additions to this file to: ++ bug-gdb@prep.ai.mit.edu */ ++ ++__thread int var = 42; +--- /dev/null 2009-02-10 00:19:00.494289687 +0100 ++++ gdb-6.8.50.20090209-x/gdb/testsuite/gdb.threads/tls-sepdebug.exp 2009-02-10 00:49:38.000000000 +0100 +@@ -0,0 +1,86 @@ ++# Copyright 2006 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++if $tracelevel then { ++ strace $tracelevel ++} ++ ++set testfile tls-sepdebug ++set srcmainfile ${testfile}-main.c ++set srcsharedfile ${testfile}-shared.c ++ ++set binmainfile ${objdir}/${subdir}/${testfile}-main ++set binsharedbase ${testfile}-shared.so ++set binsharedfile ${objdir}/${subdir}/${binsharedbase} ++set binshareddebugfile ${objdir}/${subdir}/${binsharedbase}.debug ++ ++# Use explicit -soname as otherwise the full path to the library would get ++# encoded into ${binmainfile} making LD_LIBRARY_PATH tests useless. ++ ++# FIXME: gcc dependency (-Wl,-soname). ++ ++if { [gdb_compile_shlib "${srcdir}/${subdir}/${srcsharedfile}" "${binsharedfile}" [list debug additional_flags=-Wl,-soname=${binsharedbase}]] != "" } { ++ untested "Couldn't compile test library" ++ return -1 ++} ++ ++# eu-strip(1) works fine but it is a part of `elfutils', not `binutils'. ++if 0 then { ++ remote_exec build "eu-strip -f ${binshareddebugfile} ${binsharedfile}" ++} else { ++ remote_exec build "objcopy --only-keep-debug ${binsharedfile} ${binshareddebugfile}" ++ remote_exec build "objcopy --strip-debug ${binsharedfile}" ++ remote_exec build "objcopy --add-gnu-debuglink=${binshareddebugfile} ${binsharedfile}" ++} ++ ++# Do not use `shlib=' as it will automatically add also -rpath for gcc. ++ ++if { [gdb_compile_pthreads "${srcdir}/${subdir}/${srcmainfile} ${binsharedfile}" "${binmainfile}" executable {debug}] != "" } { ++ untested "Couldn't compile test program" ++ return -1 ++} ++ ++# Get things started. ++ ++# Test also the proper resolving of relative library names to absolute ones. ++# \$PWD is easy - it is the absolute way ++# ${subdir} would fail on "print var" ++ ++foreach ld_library_path [list [pwd]/${subdir} ./${subdir}] name { absolute relative } { ++ ++ gdb_exit ++ gdb_start ++ ###gdb_reinitialize_dir $srcdir/$subdir ++ ++ gdb_test "set env LD_LIBRARY_PATH=$ld_library_path" \ ++ "" \ ++ "set env LD_LIBRARY_PATH is $name" ++ ++ gdb_load ${binmainfile} ++ ++ # For C programs, "start" should stop in main(). ++ ++ gdb_test "start" \ ++ "main \\(\\) at .*${srcmainfile}.*" \ ++ "start" ++ ++ # Check for: Cannot find shared library `/usr/lib/debug/lib/libc-2.4.90.so.debug' in dynamic linker's load module list ++ # as happens with TLS variables and `separate_debug_objfile_backlink'. ++ ++ gdb_test "print var" \ ++ "\\\$1 = \[0-9\].*" \ ++ "print TLS variable from a shared library with $name-directory separate debug info file" ++} diff --git a/gdb-6.5-tls-of-separate-debuginfo.patch b/gdb-6.5-tls-of-separate-debuginfo.patch new file mode 100644 index 0000000..b838081 --- /dev/null +++ b/gdb-6.5-tls-of-separate-debuginfo.patch @@ -0,0 +1,24 @@ +Dependency on: gdb-6.5-bz185337-resolve-tls-without-debuginfo-v2.patch + + +2006-09-01 Jan Kratochvil + + * target.c (target_translate_tls_address): Fix for separate debuginfo. + + +diff -rup gdb-6.5.orig/gdb/target.c gdb-6.5/gdb/target.c +--- gdb-6.5.orig/gdb/target.c 2006-09-20 17:13:35.000000000 -0400 ++++ gdb-6.5/gdb/target.c 2006-09-20 17:15:53.000000000 -0400 +@@ -769,6 +769,12 @@ target_translate_tls_address (struct obj + ptid_t ptid = inferior_ptid; + volatile struct gdb_exception ex; + ++ /* Resolve: Cannot find shared library ++ `/usr/lib/debug/lib/lib....so.debug' in dynamic linker's load ++ module list */ ++ if (objfile->separate_debug_objfile_backlink != NULL) ++ objfile = objfile->separate_debug_objfile_backlink; ++ + TRY_CATCH (ex, RETURN_MASK_ALL) + { + CORE_ADDR lm_addr; diff --git a/gdb-6.6-buildid-locate-rpm.patch b/gdb-6.6-buildid-locate-rpm.patch new file mode 100644 index 0000000..985855b --- /dev/null +++ b/gdb-6.6-buildid-locate-rpm.patch @@ -0,0 +1,1660 @@ +Index: gdb-6.8.50.20090302/gdb/event-top.c +=================================================================== +--- gdb-6.8.50.20090302.orig/gdb/event-top.c 2009-03-07 17:13:33.000000000 +0100 ++++ gdb-6.8.50.20090302/gdb/event-top.c 2009-03-07 17:25:06.000000000 +0100 +@@ -33,6 +33,7 @@ + #include "cli/cli-script.h" /* for reset_command_nest_depth */ + #include "main.h" + #include "gdbthread.h" ++#include "symfile.h" + + /* For dont_repeat() */ + #include "gdbcmd.h" +@@ -193,6 +194,8 @@ cli_command_loop (void) + char *a_prompt; + char *gdb_prompt = get_prompt (); + ++ debug_flush_missing (); ++ + /* Tell readline what the prompt to display is and what function it + will need to call after a whole line is read. This also displays + the first prompt. */ +@@ -264,6 +267,8 @@ display_gdb_prompt (char *new_prompt) + /* Reset the nesting depth used when trace-commands is set. */ + reset_command_nest_depth (); + ++ debug_flush_missing (); ++ + /* Each interpreter has its own rules on displaying the command + prompt. */ + if (!current_interp_display_prompt_p ()) +Index: gdb-6.8.50.20090302/gdb/symfile.c +=================================================================== +--- gdb-6.8.50.20090302.orig/gdb/symfile.c 2009-03-07 17:22:21.000000000 +0100 ++++ gdb-6.8.50.20090302/gdb/symfile.c 2009-03-07 17:26:47.000000000 +0100 +@@ -55,6 +55,7 @@ + #include "solib.h" + #include "remote.h" + #include "libbfd.h" ++#include "elf/external.h" + + #include + #include +@@ -63,6 +64,7 @@ + #include + #include + #include ++#include + + + int (*deprecated_ui_load_progress_hook) (const char *section, unsigned long num); +@@ -1684,8 +1686,352 @@ build_id_to_filename (struct build_id *b + return retval; + } + ++#ifdef HAVE_LIBRPM ++ ++#include ++#include ++#include ++#include ++#ifdef DLOPEN_LIBRPM ++#include ++#endif ++ ++/* This MISSING_RPM_HASH tracker is used to collect all the missing rpm files ++ and avoid their duplicities during a single inferior run. */ ++ ++static struct htab *missing_rpm_hash; ++ ++/* This MISSING_RPM_LIST tracker is used to collect and print as a single line ++ all the rpms right before the nearest GDB prompt. It gets cleared after ++ each such print (it is questionable if we should clear it after the print). ++ */ ++ ++struct missing_rpm ++ { ++ struct missing_rpm *next; ++ char rpm[1]; ++ }; ++static struct missing_rpm *missing_rpm_list; ++static int missing_rpm_list_entries; ++ ++/* Returns the count of newly added rpms. */ ++ ++static int ++missing_rpm_enlist (const char *filename) ++{ ++ static int rpm_init_done = 0; ++ rpmts ts; ++ rpmdbMatchIterator mi; ++ int count = 0; ++ ++#ifdef DLOPEN_LIBRPM ++ /* Duplicate here the declarations to verify they match. The same sanity ++ check is present also in `configure.ac'. */ ++ extern char * headerFormat(Header h, const char * fmt, errmsg_t * errmsg); ++ static char *(*headerFormat_p) (Header h, const char * fmt, errmsg_t *errmsg); ++ extern int rpmReadConfigFiles(const char * file, const char * target); ++ static int (*rpmReadConfigFiles_p) (const char * file, const char * target); ++ extern rpmdbMatchIterator rpmdbFreeIterator(rpmdbMatchIterator mi); ++ static rpmdbMatchIterator (*rpmdbFreeIterator_p) (rpmdbMatchIterator mi); ++ extern Header rpmdbNextIterator(rpmdbMatchIterator mi); ++ static Header (*rpmdbNextIterator_p) (rpmdbMatchIterator mi); ++ extern rpmts rpmtsCreate(void); ++ static rpmts (*rpmtsCreate_p) (void); ++ extern rpmts rpmtsFree(rpmts ts); ++ static rpmts (*rpmtsFree_p) (rpmts ts); ++ extern rpmdbMatchIterator rpmtsInitIterator(const rpmts ts, rpmTag rpmtag, ++ const void * keyp, size_t keylen); ++ static rpmdbMatchIterator (*rpmtsInitIterator_p) (const rpmts ts, ++ rpmTag rpmtag, ++ const void *keyp, ++ size_t keylen); ++#else /* !DLOPEN_LIBRPM */ ++# define headerFormat_p headerFormat ++# define rpmReadConfigFiles_p rpmReadConfigFiles ++# define rpmdbFreeIterator_p rpmdbFreeIterator ++# define rpmdbNextIterator_p rpmdbNextIterator ++# define rpmtsCreate_p rpmtsCreate ++# define rpmtsFree_p rpmtsFree ++# define rpmtsInitIterator_p rpmtsInitIterator ++#endif /* !DLOPEN_LIBRPM */ ++ ++ if (filename == NULL) ++ return 0; ++ ++ if (!rpm_init_done) ++ { ++ static int init_tried; ++ ++ /* Already failed the initialization before? */ ++ if (init_tried) ++ return 0; ++ init_tried = 1; ++ ++#ifdef DLOPEN_LIBRPM ++ { ++ void *h; ++ ++ h = dlopen (DLOPEN_LIBRPM, RTLD_LAZY); ++ if (!h) ++ { ++ warning (_("Unable to open \"%s\" (%s), " ++ "missing debuginfos notifications will not be displayed"), ++ DLOPEN_LIBRPM, dlerror ()); ++ return 0; ++ } ++ ++ if (!((headerFormat_p = dlsym (h, "headerFormat")) ++ && (rpmReadConfigFiles_p = dlsym (h, "rpmReadConfigFiles")) ++ && (rpmdbFreeIterator_p = dlsym (h, "rpmdbFreeIterator")) ++ && (rpmdbNextIterator_p = dlsym (h, "rpmdbNextIterator")) ++ && (rpmtsCreate_p = dlsym (h, "rpmtsCreate")) ++ && (rpmtsFree_p = dlsym (h, "rpmtsFree")) ++ && (rpmtsInitIterator_p = dlsym (h, "rpmtsInitIterator")))) ++ { ++ warning (_("Opened library \"%s\" is incompatible (%s), " ++ "missing debuginfos notifications will not be displayed"), ++ DLOPEN_LIBRPM, dlerror ()); ++ if (dlclose (h)) ++ warning (_("Error closing library \"%s\": %s\n"), DLOPEN_LIBRPM, ++ dlerror ()); ++ return 0; ++ } ++ } ++#endif /* DLOPEN_LIBRPM */ ++ ++ if (rpmReadConfigFiles_p (NULL, NULL) != 0) ++ { ++ warning (_("Error reading the rpm configuration files")); ++ return 0; ++ } ++ ++ rpm_init_done = 1; ++ } ++ ++ ts = rpmtsCreate_p (); ++ ++ mi = rpmtsInitIterator_p (ts, RPMTAG_BASENAMES, filename, 0); ++ if (mi != NULL) ++ { ++ for (;;) ++ { ++ Header h; ++ char *debuginfo, **slot, *s, *s2; ++ errmsg_t err; ++ size_t srcrpmlen = sizeof (".src.rpm") - 1; ++ size_t debuginfolen = sizeof ("-debuginfo") - 1; ++ rpmdbMatchIterator mi_debuginfo; ++ ++ h = rpmdbNextIterator_p (mi); ++ if (h == NULL) ++ break; ++ ++ /* Verify the debuginfo file is not already installed. */ ++ ++ debuginfo = headerFormat_p (h, "%{sourcerpm}-debuginfo.%{arch}", ++ &err); ++ if (!debuginfo) ++ { ++ warning (_("Error querying the rpm file `%s': %s"), filename, ++ err); ++ continue; ++ } ++ /* s = `.src.rpm-debuginfo.%{arch}' */ ++ s = strrchr (debuginfo, '-') - srcrpmlen; ++ s2 = NULL; ++ if (s > debuginfo && memcmp (s, ".src.rpm", srcrpmlen) == 0) ++ { ++ /* s2 = `-%{release}.src.rpm-debuginfo.%{arch}' */ ++ s2 = memrchr (debuginfo, '-', s - debuginfo); ++ } ++ if (s2) ++ { ++ /* s2 = `-%{version}-%{release}.src.rpm-debuginfo.%{arch}' */ ++ s2 = memrchr (debuginfo, '-', s2 - debuginfo); ++ } ++ if (!s2) ++ { ++ warning (_("Error querying the rpm file `%s': %s"), filename, ++ debuginfo); ++ xfree (debuginfo); ++ continue; ++ } ++ /* s = `.src.rpm-debuginfo.%{arch}' */ ++ /* s2 = `-%{version}-%{release}.src.rpm-debuginfo.%{arch}' */ ++ memmove (s2 + debuginfolen, s2, s - s2); ++ memcpy (s2, "-debuginfo", debuginfolen); ++ /* s = `XXXX.%{arch}' */ ++ /* strlen ("XXXX") == srcrpmlen + debuginfolen */ ++ /* s2 = `-debuginfo-%{version}-%{release}XX.%{arch}' */ ++ /* strlen ("XX") == srcrpmlen */ ++ memmove (s + debuginfolen, s + srcrpmlen + debuginfolen, ++ strlen (s + srcrpmlen + debuginfolen) + 1); ++ /* s = `-debuginfo-%{version}-%{release}.%{arch}' */ ++ ++ /* RPMDBI_PACKAGES requires keylen == sizeof (int). */ ++ /* RPMDBI_LABEL is an interface for NVR-based dbiFindByLabel(). */ ++ mi_debuginfo = rpmtsInitIterator_p (ts, RPMDBI_LABEL, debuginfo, 0); ++ xfree (debuginfo); ++ if (mi_debuginfo) ++ { ++ rpmdbFreeIterator_p (mi_debuginfo); ++ count = 0; ++ break; ++ } ++ ++ /* The allocated memory gets utilized below for MISSING_RPM_HASH. */ ++ debuginfo = headerFormat_p (h, ++ "%{name}-%{version}-%{release}.%{arch}", ++ &err); ++ if (!debuginfo) ++ { ++ warning (_("Error querying the rpm file `%s': %s"), filename, ++ err); ++ continue; ++ } ++ ++ /* Base package name for `debuginfo-install'. We do not use the ++ `yum' command directly as the line ++ yum --enablerepo='*-debuginfo' install NAME-debuginfo.ARCH ++ would be more complicated than just: ++ debuginfo-install NAME-VERSION-RELEASE.ARCH ++ Do not supply the rpm base name (derived from .src.rpm name) as ++ debuginfo-install is unable to install the debuginfo package if ++ the base name PKG binary rpm is not installed while for example ++ PKG-libs would be installed (RH Bug 467901). ++ FUTURE: After multiple debuginfo versions simultaneously installed ++ get supported the support for the VERSION-RELEASE tags handling ++ may need an update. */ ++ ++ if (missing_rpm_hash == NULL) ++ { ++ /* DEL_F is passed NULL as MISSING_RPM_LIST's HTAB_DELETE ++ should not deallocate the entries. */ ++ ++ missing_rpm_hash = htab_create_alloc (64, htab_hash_string, ++ (int (*) (const void *, const void *)) streq, ++ NULL, xcalloc, xfree); ++ } ++ slot = (char **) htab_find_slot (missing_rpm_hash, debuginfo, INSERT); ++ /* XCALLOC never returns NULL. */ ++ gdb_assert (slot != NULL); ++ if (*slot == NULL) ++ { ++ struct missing_rpm *missing_rpm; ++ ++ *slot = debuginfo; ++ ++ missing_rpm = xmalloc (sizeof (*missing_rpm) + strlen (debuginfo)); ++ strcpy (missing_rpm->rpm, debuginfo); ++ missing_rpm->next = missing_rpm_list; ++ missing_rpm_list = missing_rpm; ++ missing_rpm_list_entries++; ++ } ++ else ++ xfree (debuginfo); ++ count++; ++ } ++ ++ rpmdbFreeIterator_p (mi); ++ } ++ ++ rpmtsFree_p (ts); ++ ++ return count; ++} ++ ++static int ++missing_rpm_list_compar (const char *const *ap, const char *const *bp) ++{ ++ return strcoll (*ap, *bp); ++} ++ ++/* It returns a NULL-terminated array of strings needing to be FREEd. It may ++ also return only NULL. */ ++ ++static void ++missing_rpm_list_print (void) ++{ ++ char **array, **array_iter; ++ struct missing_rpm *list_iter; ++ struct cleanup *cleanups; ++ ++ if (missing_rpm_list_entries == 0) ++ return; ++ ++ array = xmalloc (sizeof (*array) * missing_rpm_list_entries); ++ cleanups = make_cleanup (xfree, array); ++ ++ array_iter = array; ++ for (list_iter = missing_rpm_list; list_iter != NULL; ++ list_iter = list_iter->next) ++ { ++ *array_iter++ = list_iter->rpm; ++ } ++ gdb_assert (array_iter == array + missing_rpm_list_entries); ++ ++ qsort (array, missing_rpm_list_entries, sizeof (*array), ++ (int (*) (const void *, const void *)) missing_rpm_list_compar); ++ ++ printf_unfiltered (_("Missing separate debuginfos, use: %s"), ++ "debuginfo-install"); ++ for (array_iter = array; array_iter < array + missing_rpm_list_entries; ++ array_iter++) ++ { ++ putchar_unfiltered (' '); ++ puts_unfiltered (*array_iter); ++ } ++ putchar_unfiltered ('\n'); ++ ++ while (missing_rpm_list != NULL) ++ { ++ list_iter = missing_rpm_list; ++ missing_rpm_list = list_iter->next; ++ xfree (list_iter); ++ } ++ missing_rpm_list_entries = 0; ++ ++ do_cleanups (cleanups); ++} ++ ++static void ++missing_rpm_change (void) ++{ ++ debug_flush_missing (); ++ ++ gdb_assert (missing_rpm_list == NULL); ++ if (missing_rpm_hash != NULL) ++ { ++ htab_delete (missing_rpm_hash); ++ missing_rpm_hash = NULL; ++ } ++} ++ ++enum missing_exec ++ { ++ /* Init state. EXEC_BFD also still could be NULL. */ ++ MISSING_EXEC_NOT_TRIED, ++ /* We saw a non-NULL EXEC_BFD but RPM has no info about it. */ ++ MISSING_EXEC_NOT_FOUND, ++ /* We found EXEC_BFD by RPM and we either have its symbols (either embedded ++ or separate) or the main executable's RPM is now contained in ++ MISSING_RPM_HASH. */ ++ MISSING_EXEC_ENLISTED ++ }; ++static enum missing_exec missing_exec = MISSING_EXEC_NOT_TRIED; ++ ++#endif /* HAVE_LIBRPM */ ++ ++void ++debug_flush_missing (void) ++{ ++#ifdef HAVE_LIBRPM ++ missing_rpm_list_print (); ++#endif ++} ++ + /* This MISSING_FILEPAIR_HASH tracker is used only for the duplicite messages +- Try to install the hash file ... ++ yum --enablerepo='*-debuginfo' install ... + avoidance. */ + + struct missing_filepair +@@ -1739,11 +2085,17 @@ missing_filepair_change (void) + /* All their memory came just from missing_filepair_OBSTACK. */ + missing_filepair_hash = NULL; + } ++#ifdef HAVE_LIBRPM ++ missing_exec = MISSING_EXEC_NOT_TRIED; ++#endif + } + + static void + debug_print_executable_changed (void) + { ++#ifdef HAVE_LIBRPM ++ missing_rpm_change (); ++#endif + missing_filepair_change (); + } + +@@ -1802,14 +2154,33 @@ debug_print_missing (const char *binary, + } + *slot = missing_filepair; + +- /* We do not collect and flush these messages as each such message +- already requires its own separate lines. */ ++#ifdef HAVE_LIBRPM ++ if (missing_exec == MISSING_EXEC_NOT_TRIED) ++ { ++ char *exec_filename; + +- fprintf_unfiltered (gdb_stdlog, +- _("Missing separate debuginfo for %s\n"), binary); +- if (debug != NULL) +- fprintf_unfiltered (gdb_stdlog, _("Try to install the hash file %s\n"), +- debug); ++ exec_filename = get_exec_file (0); ++ if (exec_filename != NULL) ++ { ++ if (missing_rpm_enlist (exec_filename) == 0) ++ missing_exec = MISSING_EXEC_NOT_FOUND; ++ else ++ missing_exec = MISSING_EXEC_ENLISTED; ++ } ++ } ++ if (missing_exec != MISSING_EXEC_ENLISTED) ++ if (missing_rpm_enlist (binary) == 0 && missing_rpm_enlist (debug) == 0) ++#endif /* HAVE_LIBRPM */ ++ { ++ /* We do not collect and flush these messages as each such message ++ already requires its own separate lines. */ ++ ++ fprintf_unfiltered (gdb_stdlog, ++ _("Missing separate debuginfo for %s\n"), binary); ++ if (debug != NULL) ++ fprintf_unfiltered (gdb_stdlog, _("Try: %s %s\n"), ++ "yum --enablerepo='*-debuginfo' install", debug); ++ } + } + + static char * +Index: gdb-6.8.50.20090302/gdb/symfile.h +=================================================================== +--- gdb-6.8.50.20090302.orig/gdb/symfile.h 2009-03-07 17:13:33.000000000 +0100 ++++ gdb-6.8.50.20090302/gdb/symfile.h 2009-03-07 17:25:06.000000000 +0100 +@@ -378,6 +378,7 @@ extern struct build_id *build_id_addr_ge + extern char *build_id_to_filename (struct build_id *build_id, + char **link_return, int add_debug_suffix); + extern void debug_print_missing (const char *binary, const char *debug); ++extern void debug_flush_missing (void); + + /* From dwarf2read.c */ + +Index: gdb-6.8.50.20090302/gdb/testsuite/lib/gdb.exp +=================================================================== +--- gdb-6.8.50.20090302.orig/gdb/testsuite/lib/gdb.exp 2009-03-07 17:13:33.000000000 +0100 ++++ gdb-6.8.50.20090302/gdb/testsuite/lib/gdb.exp 2009-03-07 17:25:06.000000000 +0100 +@@ -1230,7 +1230,7 @@ proc default_gdb_start { } { + warning "Couldn't set the width to 0." + } + } +- # Turn off the missing warnings as the testsuite does not expect it. ++ # Turn off the missing RPMs warnings as the testsuite does not expect it. + send_gdb "set build-id-verbose 0\n" + gdb_expect 10 { + -re "$gdb_prompt $" { +Index: gdb-6.8.50.20090302/gdb/tui/tui-interp.c +=================================================================== +--- gdb-6.8.50.20090302.orig/gdb/tui/tui-interp.c 2009-03-07 17:13:33.000000000 +0100 ++++ gdb-6.8.50.20090302/gdb/tui/tui-interp.c 2009-03-07 17:25:06.000000000 +0100 +@@ -30,6 +30,7 @@ + #include "tui/tui.h" + #include "tui/tui-io.h" + #include "exceptions.h" ++#include "symfile.h" + + /* Set to 1 when the TUI mode must be activated when we first start + gdb. */ +@@ -128,6 +129,8 @@ tui_command_loop (void *data) + char *a_prompt; + char *gdb_prompt = get_prompt (); + ++ debug_flush_missing (); ++ + /* Tell readline what the prompt to display is and what function + it will need to call after a whole line is read. This also + displays the first prompt. */ +Index: gdb-6.8.50.20090302/gdb/aclocal.m4 +=================================================================== +--- gdb-6.8.50.20090302.orig/gdb/aclocal.m4 2009-03-07 17:13:33.000000000 +0100 ++++ gdb-6.8.50.20090302/gdb/aclocal.m4 2009-03-07 17:25:06.000000000 +0100 +@@ -11,6 +11,162 @@ + # even the implied warranty of MERCHANTABILITY or FITNESS FOR A + # PARTICULAR PURPOSE. + ++# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- ++# ++# Copyright © 2004 Scott James Remnant . ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, but ++# WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++# General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++# ++# As a special exception to the GNU General Public License, if you ++# distribute this file as part of a program that contains a ++# configuration script generated by Autoconf, you may include it under ++# the same distribution terms that you use for the rest of that program. ++ ++# PKG_PROG_PKG_CONFIG([MIN-VERSION]) ++# ---------------------------------- ++AC_DEFUN([PKG_PROG_PKG_CONFIG], ++[m4_pattern_forbid([^_?PKG_[A-Z_]+$]) ++m4_pattern_allow([^PKG_CONFIG(_PATH)?$]) ++AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])dnl ++if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then ++ AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) ++fi ++if test -n "$PKG_CONFIG"; then ++ _pkg_min_version=m4_default([$1], [0.9.0]) ++ AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) ++ if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then ++ AC_MSG_RESULT([yes]) ++ else ++ AC_MSG_RESULT([no]) ++ PKG_CONFIG="" ++ fi ++ ++fi[]dnl ++])# PKG_PROG_PKG_CONFIG ++ ++# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) ++# ++# Check to see whether a particular set of modules exists. Similar ++# to PKG_CHECK_MODULES(), but does not set variables or print errors. ++# ++# ++# Similar to PKG_CHECK_MODULES, make sure that the first instance of ++# this or PKG_CHECK_MODULES is called, or make sure to call ++# PKG_CHECK_EXISTS manually ++# -------------------------------------------------------------- ++AC_DEFUN([PKG_CHECK_EXISTS], ++[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl ++if test -n "$PKG_CONFIG" && \ ++ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then ++ m4_ifval([$2], [$2], [:]) ++m4_ifvaln([$3], [else ++ $3])dnl ++fi]) ++ ++ ++# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) ++# --------------------------------------------- ++m4_define([_PKG_CONFIG], ++[if test -n "$$1"; then ++ pkg_cv_[]$1="$$1" ++ elif test -n "$PKG_CONFIG"; then ++ PKG_CHECK_EXISTS([$3], ++ [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`], ++ [pkg_failed=yes]) ++ else ++ pkg_failed=untried ++fi[]dnl ++])# _PKG_CONFIG ++ ++# _PKG_SHORT_ERRORS_SUPPORTED ++# ----------------------------- ++AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], ++[AC_REQUIRE([PKG_PROG_PKG_CONFIG]) ++if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then ++ _pkg_short_errors_supported=yes ++else ++ _pkg_short_errors_supported=no ++fi[]dnl ++])# _PKG_SHORT_ERRORS_SUPPORTED ++ ++ ++# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], ++# [ACTION-IF-NOT-FOUND]) ++# ++# ++# Note that if there is a possibility the first call to ++# PKG_CHECK_MODULES might not happen, you should be sure to include an ++# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac ++# ++# ++# -------------------------------------------------------------- ++AC_DEFUN([PKG_CHECK_MODULES], ++[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl ++AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl ++AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl ++ ++pkg_failed=no ++AC_MSG_CHECKING([for $1]) ++ ++_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) ++_PKG_CONFIG([$1][_LIBS], [libs], [$2]) ++ ++m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS ++and $1[]_LIBS to avoid the need to call pkg-config. ++See the pkg-config man page for more details.]) ++ ++if test $pkg_failed = yes; then ++ _PKG_SHORT_ERRORS_SUPPORTED ++ if test $_pkg_short_errors_supported = yes; then ++ $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "$2" 2>&1` ++ else ++ $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors "$2" 2>&1` ++ fi ++ # Put the nasty error message in config.log where it belongs ++ echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD ++ ++ ifelse([$4], , [AC_MSG_ERROR(dnl ++[Package requirements ($2) were not met: ++ ++$$1_PKG_ERRORS ++ ++Consider adjusting the PKG_CONFIG_PATH environment variable if you ++installed software in a non-standard prefix. ++ ++_PKG_TEXT ++])], ++ [AC_MSG_RESULT([no]) ++ $4]) ++elif test $pkg_failed = untried; then ++ ifelse([$4], , [AC_MSG_FAILURE(dnl ++[The pkg-config script could not be found or is too old. Make sure it ++is in your PATH or set the PKG_CONFIG environment variable to the full ++path to pkg-config. ++ ++_PKG_TEXT ++ ++To get pkg-config, see .])], ++ [$4]) ++else ++ $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS ++ $1[]_LIBS=$pkg_cv_[]$1[]_LIBS ++ AC_MSG_RESULT([yes]) ++ ifelse([$3], , :, [$3]) ++fi[]dnl ++])# PKG_CHECK_MODULES ++ + # Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. + # + # This file is free software; the Free Software Foundation +@@ -468,6 +624,27 @@ AC_DEFUN([AM_PROG_INSTALL_SH], + install_sh=${install_sh-"$am_aux_dir/install-sh"} + AC_SUBST(install_sh)]) + ++# Copyright (C) 2003, 2005 Free Software Foundation, Inc. ++# ++# This file is free software; the Free Software Foundation ++# gives unlimited permission to copy and/or distribute it, ++# with or without modifications, as long as this notice is preserved. ++ ++# serial 2 ++ ++# Check whether the underlying file-system supports filenames ++# with a leading dot. For instance MS-DOS doesn't. ++AC_DEFUN([AM_SET_LEADING_DOT], ++[rm -rf .tst 2>/dev/null ++mkdir .tst 2>/dev/null ++if test -d .tst; then ++ am__leading_dot=. ++else ++ am__leading_dot=_ ++fi ++rmdir .tst 2>/dev/null ++AC_SUBST([am__leading_dot])]) ++ + # Add --enable-maintainer-mode option to configure. -*- Autoconf -*- + # From Jim Meyering + +@@ -868,7 +1045,4 @@ m4_include([gnulib/m4/onceonly_2_57.m4]) + m4_include([gnulib/m4/stdint.m4]) + m4_include([gnulib/m4/string_h.m4]) + m4_include([gnulib/m4/wchar.m4]) +-m4_include([../config/extensions.m4]) +-m4_include([../config/lead-dot.m4]) +-m4_include([../config/proginstall.m4]) + m4_include([acinclude.m4]) +Index: gdb-6.8.50.20090302/gdb/config.in +=================================================================== +--- gdb-6.8.50.20090302.orig/gdb/config.in 2009-03-07 17:13:33.000000000 +0100 ++++ gdb-6.8.50.20090302/gdb/config.in 2009-03-07 17:25:06.000000000 +0100 +@@ -38,6 +38,9 @@ + /* Define to BFD's default target vector. */ + #undef DEFAULT_BFD_VEC + ++/* librpm version specific library name to dlopen. */ ++#undef DLOPEN_LIBRPM ++ + /* Define to 1 if translation of program messages to the user's native + language is requested. */ + #undef ENABLE_NLS +@@ -211,6 +214,9 @@ + /* Define if Python 2.6 is being used. */ + #undef HAVE_LIBPYTHON2_6 + ++/* Define if librpm library is being used. */ ++#undef HAVE_LIBRPM ++ + /* Define if libunwind library is being used. */ + #undef HAVE_LIBUNWIND + +Index: gdb-6.8.50.20090302/gdb/configure +=================================================================== +--- gdb-6.8.50.20090302.orig/gdb/configure 2009-03-07 17:13:33.000000000 +0100 ++++ gdb-6.8.50.20090302/gdb/configure 2009-03-07 17:25:06.000000000 +0100 +@@ -314,7 +314,7 @@ ac_subdirs_all="$ac_subdirs_all doc test + ac_subdirs_all="$ac_subdirs_all gdbtk" + ac_subdirs_all="$ac_subdirs_all multi-ice" + ac_subdirs_all="$ac_subdirs_all gdbserver" +-ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CPP EGREP RANLIB ac_ct_RANLIB build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os am__leading_dot DEPDIR CCDEPMODE MAKE GMAKE_TRUE GMAKE_FALSE SET_MAKE USE_NLS LIBINTL LIBINTL_DEP INCINTL XGETTEXT GMSGFMT POSUB CATALOGS DATADIRNAME INSTOBJEXT GENCAT CATOBJEXT localedir GL_COND_LIBTOOL_TRUE GL_COND_LIBTOOL_FALSE GNULIB_MEMMEM GNULIB_MEMPCPY GNULIB_MEMRCHR GNULIB_STPCPY GNULIB_STPNCPY GNULIB_STRCHRNUL GNULIB_STRDUP GNULIB_STRNDUP GNULIB_STRNLEN GNULIB_STRPBRK GNULIB_STRSEP GNULIB_STRSTR GNULIB_STRCASESTR GNULIB_STRTOK_R GNULIB_MBSLEN GNULIB_MBSNLEN GNULIB_MBSCHR GNULIB_MBSRCHR GNULIB_MBSSTR GNULIB_MBSCASECMP GNULIB_MBSNCASECMP GNULIB_MBSPCASECMP GNULIB_MBSCASESTR GNULIB_MBSCSPN GNULIB_MBSPBRK GNULIB_MBSSPN GNULIB_MBSSEP GNULIB_MBSTOK_R GNULIB_STRERROR GNULIB_STRSIGNAL HAVE_DECL_MEMMEM HAVE_MEMPCPY HAVE_DECL_MEMRCHR HAVE_STPCPY HAVE_STPNCPY HAVE_STRCHRNUL HAVE_DECL_STRDUP HAVE_STRNDUP HAVE_DECL_STRNDUP HAVE_DECL_STRNLEN HAVE_STRPBRK HAVE_STRSEP HAVE_STRCASESTR HAVE_DECL_STRTOK_R HAVE_DECL_STRERROR HAVE_DECL_STRSIGNAL REPLACE_STRERROR REPLACE_STRSIGNAL REPLACE_MEMMEM REPLACE_STRCASESTR REPLACE_STRSTR HAVE_LONG_LONG_INT HAVE_UNSIGNED_LONG_LONG_INT HAVE_INTTYPES_H HAVE_SYS_TYPES_H INCLUDE_NEXT NEXT_STDINT_H HAVE_STDINT_H HAVE_SYS_INTTYPES_H HAVE_SYS_BITYPES_H BITSIZEOF_PTRDIFF_T BITSIZEOF_SIG_ATOMIC_T BITSIZEOF_SIZE_T BITSIZEOF_WCHAR_T BITSIZEOF_WINT_T HAVE_SIGNED_SIG_ATOMIC_T HAVE_SIGNED_WCHAR_T HAVE_SIGNED_WINT_T PTRDIFF_T_SUFFIX SIG_ATOMIC_T_SUFFIX SIZE_T_SUFFIX WCHAR_T_SUFFIX WINT_T_SUFFIX STDINT_H NEXT_STRING_H GNULIB_WCWIDTH HAVE_DECL_WCWIDTH REPLACE_WCWIDTH WCHAR_H HAVE_WCHAR_H NEXT_WCHAR_H LIBGNU_LIBDEPS LIBGNU_LTLIBDEPS GNULIB_STDINT_H PACKAGE INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK AMTAR am__tar am__untar am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH am__fastdepCC_TRUE am__fastdepCC_FALSE GDB_DATADIR_PATH pythondir subdirs TARGET_OBS PKGVERSION REPORT_BUGS_TO REPORT_BUGS_TEXI LN_S YACC AR ac_ct_AR DLLTOOL ac_ct_DLLTOOL WINDRES ac_ct_WINDRES MIG ac_ct_MIG LIBICONV LIBICONV_INCLUDE LIBICONV_LIBDIR READLINE READLINE_DEPS READLINE_CFLAGS HAVE_LIBEXPAT LIBEXPAT LTLIBEXPAT PYTHON_CFLAGS ALLOCA CONFIG_LDFLAGS TARGET_SYSTEM_ROOT TARGET_SYSTEM_ROOT_DEFINE WARN_CFLAGS WERROR_CFLAGS SER_HARDWIRE WIN32LIBS LIBGUI GUI_CFLAGS_X WIN32LDAPP TCL_VERSION TCL_PATCH_LEVEL TCL_BIN_DIR TCL_SRC_DIR TCL_LIB_FILE TCL_LIB_FLAG TCL_LIB_SPEC TCL_STUB_LIB_FILE TCL_STUB_LIB_FLAG TCL_STUB_LIB_SPEC TCL_INCLUDE TCL_LIBRARY TCL_DEPS TK_VERSION TK_BIN_DIR TK_SRC_DIR TK_LIB_FILE TK_LIB_FLAG TK_LIB_SPEC TK_STUB_LIB_FILE TK_STUB_LIB_FLAG TK_STUB_LIB_SPEC TK_INCLUDE TK_LIBRARY TK_DEPS TK_XINCLUDES X_CFLAGS X_LDFLAGS X_LIBS GDBTKLIBS GDBTK_CFLAGS GDBTK_SRC_DIR SIM SIM_OBS ENABLE_CFLAGS PROFILE_CFLAGS CONFIG_OBS CONFIG_DEPS CONFIG_SRCS CONFIG_ALL CONFIG_CLEAN CONFIG_INSTALL CONFIG_UNINSTALL target_subdir frags nm_h LIBOBJS LTLIBOBJS gl_LIBOBJS gl_LTLIBOBJS gltests_LIBOBJS gltests_LTLIBOBJS' ++ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CPP EGREP RANLIB ac_ct_RANLIB build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os am__leading_dot DEPDIR CCDEPMODE MAKE GMAKE_TRUE GMAKE_FALSE SET_MAKE USE_NLS LIBINTL LIBINTL_DEP INCINTL XGETTEXT GMSGFMT POSUB CATALOGS DATADIRNAME INSTOBJEXT GENCAT CATOBJEXT localedir GL_COND_LIBTOOL_TRUE GL_COND_LIBTOOL_FALSE GNULIB_MEMMEM GNULIB_MEMPCPY GNULIB_MEMRCHR GNULIB_STPCPY GNULIB_STPNCPY GNULIB_STRCHRNUL GNULIB_STRDUP GNULIB_STRNDUP GNULIB_STRNLEN GNULIB_STRPBRK GNULIB_STRSEP GNULIB_STRSTR GNULIB_STRCASESTR GNULIB_STRTOK_R GNULIB_MBSLEN GNULIB_MBSNLEN GNULIB_MBSCHR GNULIB_MBSRCHR GNULIB_MBSSTR GNULIB_MBSCASECMP GNULIB_MBSNCASECMP GNULIB_MBSPCASECMP GNULIB_MBSCASESTR GNULIB_MBSCSPN GNULIB_MBSPBRK GNULIB_MBSSPN GNULIB_MBSSEP GNULIB_MBSTOK_R GNULIB_STRERROR GNULIB_STRSIGNAL HAVE_DECL_MEMMEM HAVE_MEMPCPY HAVE_DECL_MEMRCHR HAVE_STPCPY HAVE_STPNCPY HAVE_STRCHRNUL HAVE_DECL_STRDUP HAVE_STRNDUP HAVE_DECL_STRNDUP HAVE_DECL_STRNLEN HAVE_STRPBRK HAVE_STRSEP HAVE_STRCASESTR HAVE_DECL_STRTOK_R HAVE_DECL_STRERROR HAVE_DECL_STRSIGNAL REPLACE_STRERROR REPLACE_STRSIGNAL REPLACE_MEMMEM REPLACE_STRCASESTR REPLACE_STRSTR HAVE_LONG_LONG_INT HAVE_UNSIGNED_LONG_LONG_INT HAVE_INTTYPES_H HAVE_SYS_TYPES_H INCLUDE_NEXT NEXT_STDINT_H HAVE_STDINT_H HAVE_SYS_INTTYPES_H HAVE_SYS_BITYPES_H BITSIZEOF_PTRDIFF_T BITSIZEOF_SIG_ATOMIC_T BITSIZEOF_SIZE_T BITSIZEOF_WCHAR_T BITSIZEOF_WINT_T HAVE_SIGNED_SIG_ATOMIC_T HAVE_SIGNED_WCHAR_T HAVE_SIGNED_WINT_T PTRDIFF_T_SUFFIX SIG_ATOMIC_T_SUFFIX SIZE_T_SUFFIX WCHAR_T_SUFFIX WINT_T_SUFFIX STDINT_H NEXT_STRING_H GNULIB_WCWIDTH HAVE_DECL_WCWIDTH REPLACE_WCWIDTH WCHAR_H HAVE_WCHAR_H NEXT_WCHAR_H LIBGNU_LIBDEPS LIBGNU_LTLIBDEPS GNULIB_STDINT_H PACKAGE INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK AMTAR am__tar am__untar am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH am__fastdepCC_TRUE am__fastdepCC_FALSE GDB_DATADIR_PATH pythondir PKG_CONFIG ac_pt_PKG_CONFIG RPM_CFLAGS RPM_LIBS subdirs TARGET_OBS PKGVERSION REPORT_BUGS_TO REPORT_BUGS_TEXI LN_S YACC AR ac_ct_AR DLLTOOL ac_ct_DLLTOOL WINDRES ac_ct_WINDRES MIG ac_ct_MIG LIBICONV LIBICONV_INCLUDE LIBICONV_LIBDIR READLINE READLINE_DEPS READLINE_CFLAGS HAVE_LIBEXPAT LIBEXPAT LTLIBEXPAT PYTHON_CFLAGS ALLOCA CONFIG_LDFLAGS TARGET_SYSTEM_ROOT TARGET_SYSTEM_ROOT_DEFINE WARN_CFLAGS WERROR_CFLAGS SER_HARDWIRE WIN32LIBS LIBGUI GUI_CFLAGS_X WIN32LDAPP TCL_VERSION TCL_PATCH_LEVEL TCL_BIN_DIR TCL_SRC_DIR TCL_LIB_FILE TCL_LIB_FLAG TCL_LIB_SPEC TCL_STUB_LIB_FILE TCL_STUB_LIB_FLAG TCL_STUB_LIB_SPEC TCL_INCLUDE TCL_LIBRARY TCL_DEPS TK_VERSION TK_BIN_DIR TK_SRC_DIR TK_LIB_FILE TK_LIB_FLAG TK_LIB_SPEC TK_STUB_LIB_FILE TK_STUB_LIB_FLAG TK_STUB_LIB_SPEC TK_INCLUDE TK_LIBRARY TK_DEPS TK_XINCLUDES X_CFLAGS X_LDFLAGS X_LIBS GDBTKLIBS GDBTK_CFLAGS GDBTK_SRC_DIR SIM SIM_OBS ENABLE_CFLAGS PROFILE_CFLAGS CONFIG_OBS CONFIG_DEPS CONFIG_SRCS CONFIG_ALL CONFIG_CLEAN CONFIG_INSTALL CONFIG_UNINSTALL target_subdir frags nm_h LIBOBJS LTLIBOBJS gl_LIBOBJS gl_LTLIBOBJS gltests_LIBOBJS gltests_LTLIBOBJS' + ac_subst_files='host_makefile_frag' + ac_pwd=`pwd` + +@@ -776,6 +776,18 @@ ac_env_CPP_set=${CPP+set} + ac_env_CPP_value=$CPP + ac_cv_env_CPP_set=${CPP+set} + ac_cv_env_CPP_value=$CPP ++ac_env_PKG_CONFIG_set=${PKG_CONFIG+set} ++ac_env_PKG_CONFIG_value=$PKG_CONFIG ++ac_cv_env_PKG_CONFIG_set=${PKG_CONFIG+set} ++ac_cv_env_PKG_CONFIG_value=$PKG_CONFIG ++ac_env_RPM_CFLAGS_set=${RPM_CFLAGS+set} ++ac_env_RPM_CFLAGS_value=$RPM_CFLAGS ++ac_cv_env_RPM_CFLAGS_set=${RPM_CFLAGS+set} ++ac_cv_env_RPM_CFLAGS_value=$RPM_CFLAGS ++ac_env_RPM_LIBS_set=${RPM_LIBS+set} ++ac_env_RPM_LIBS_value=$RPM_LIBS ++ac_cv_env_RPM_LIBS_set=${RPM_LIBS+set} ++ac_cv_env_RPM_LIBS_value=$RPM_LIBS + + # + # Report the --help message. +@@ -886,6 +898,8 @@ Optional Packages: + [DATADIR/gdb] + --with-pythondir install Python data files in this path + [DATADIR/gdb/python] ++ --with-rpm query rpm database for missing debuginfos ++ [yes/no,], [def.], [auto=librpm.so] + --with-libunwind Use libunwind frame unwinding support + --with-pkgversion=PKG Use PKG in the version string in place of "GDB" + --with-bugurl=URL Direct users to URL to report a bug +@@ -913,6 +927,9 @@ Some influential environment variables: + CPPFLAGS C/C++ preprocessor flags, e.g. -I if you have + headers in a nonstandard directory + CPP C preprocessor ++ PKG_CONFIG path to pkg-config utility ++ RPM_CFLAGS C compiler flags for RPM, overriding pkg-config ++ RPM_LIBS linker flags for RPM, overriding pkg-config + + Use these variables to override the choices made by `configure' or to help + it to find libraries and programs with nonstandard names/locations. +@@ -6556,7 +6573,6 @@ am__api_version="1.9" + # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" + # OS/2's system install, which has a completely different semantic + # ./install, which can be erroneously created by make from ./install.sh. +-# Reject install programs that cannot install multiple files. + echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 + echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6 + if test -z "$INSTALL"; then +@@ -6590,18 +6606,8 @@ case $as_dir/ in + # program-specific install script used by HP pwplus--don't use. + : + else +- rm -rf conftest.one conftest.two conftest.dir +- echo one > conftest.one +- echo two > conftest.two +- mkdir conftest.dir +- if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && +- test -s conftest.one && test -s conftest.two && +- test -s conftest.dir/conftest.one && +- test -s conftest.dir/conftest.two +- then +- ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" +- break 3 +- fi ++ ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" ++ break 3 + fi + fi + done +@@ -6610,16 +6616,15 @@ case $as_dir/ in + esac + done + +-rm -rf conftest.one conftest.two conftest.dir + + fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else +- # As a last resort, use the slow shell script. Don't cache a +- # value for INSTALL within a source directory, because that will ++ # As a last resort, use the slow shell script. We don't cache a ++ # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is +- # removed, or if the value is a relative name. ++ # removed, or if the path is relative. + INSTALL=$ac_install_sh + fi + fi +@@ -7202,6 +7207,559 @@ _ACEOF + fi + + ++# Integration with rpm library to support missing debuginfo suggestions. ++# --without-rpm: Disable any rpm support. ++# --with-rpm=libname.so: Try to dynamically open `libname.so' during runtime. ++# Even with runtime missing `libname.so' GDB will still other run correctly. ++# Missing `libname.so' during ./configure will abort the configuration. ++# --with-rpm=librpm.so: Like `--with-rpm=libname.so' but try to find specific ++# minor version first such as `librpm-4.6.so' as minor version differences ++# mean API+ABI incompatibility. If the specific match versioned library name ++# could not be found still open dynamically at least `librpm.so'. ++# --with-rpm: Like `--with-rpm=librpm.so' but if any of its detection fails try ++# to find librpm for compilation-time linking by pkg-config. GDB binary will ++# be probably linked with the version specific library (as `librpm-4.6.so'). ++# Failure to find librpm by pkg-config will abort the configuration. ++# (default) --with-rpm=auto: Like `--with-rpm=librpm.so' but if even pkg-config ++# cannot find librpm use to the rpmless compilation (like `--without-rpm'). ++ ++ ++# Check whether --with-rpm or --without-rpm was given. ++if test "${with_rpm+set}" = set; then ++ withval="$with_rpm" ++ ++else ++ with_rpm="auto" ++fi; ++ ++ ++ ++if test "x$with_rpm" != "xno"; then ++ if test "x$with_rpm" = "xyes"; then ++ LIBRPM="librpm.so" ++ RPM_REQUIRE=true ++ DLOPEN_REQUIRE=false ++ elif test "x$with_rpm" = "xauto"; then ++ LIBRPM="librpm.so" ++ RPM_REQUIRE=false ++ DLOPEN_REQUIRE=false ++ else ++ LIBRPM="$with_rpm" ++ RPM_REQUIRE=true ++ DLOPEN_REQUIRE=true ++ fi ++ LIBRPM_STRING='"'"$LIBRPM"'"' ++ ++ echo "$as_me:$LINENO: checking specific librpm version" >&5 ++echo $ECHO_N "checking specific librpm version... $ECHO_C" >&6 ++ HAVE_DLOPEN_LIBRPM=false ++ save_LIBS="$LIBS" ++ LIBS="$LIBS -ldl" ++ if test "$cross_compiling" = yes; then ++ { { echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 ++echo "$as_me: error: in \`$ac_pwd':" >&2;} ++{ { echo "$as_me:$LINENO: error: cannot run test program while cross compiling ++See \`config.log' for more details." >&5 ++echo "$as_me: error: cannot run test program while cross compiling ++See \`config.log' for more details." >&2;} ++ { (exit 1); exit 1; }; }; } ++else ++ cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++ ++#include ++#include ++#include ++ ++int ++main () ++{ ++ ++ void *h; ++ const char *const *rpmverp; ++ FILE *f; ++ ++ f = fopen ("conftest.out", "w"); ++ if (!f) ++ { ++ fprintf (stderr, "Cannot write \"%s\": %s\n", "conftest.out", ++ strerror (errno)); ++ return 1; ++ } ++ h = dlopen ($LIBRPM_STRING, RTLD_LAZY); ++ if (!h) ++ { ++ fprintf (stderr, "dlopen (\"%s\"): %s\n", $LIBRPM_STRING, dlerror ()); ++ return 1; ++ } ++ rpmverp = dlsym (h, "RPMVERSION"); ++ if (!rpmverp) ++ { ++ fprintf (stderr, "dlsym (\"RPMVERSION\"): %s\n", dlerror ()); ++ return 1; ++ } ++ fprintf (stderr, "RPMVERSION is: \""); ++ fprintf (stderr, "%s\"\n", *rpmverp); ++ ++ /* Try to find the specific librpm version only for "librpm.so" as we do ++ not know how to assemble the version string otherwise. */ ++ ++ if (strcmp ("librpm.so", $LIBRPM_STRING) != 0) ++ { ++ fprintf (f, "%s\n", $LIBRPM_STRING); ++ return 0; ++ } ++ else ++ { ++ char *h2_name; ++ void *h2; ++ int major, minor; ++ ++ if (sscanf (*rpmverp, "%d.%d", &major, &minor) != 2) ++ { ++ fprintf (stderr, "Unable to parse RPMVERSION.\n"); ++ fprintf (f, "%s\n", $LIBRPM_STRING); ++ return 0; ++ } ++ /* Avoid the square brackets by malloc. */ ++ h2_name = malloc (64); ++ sprintf (h2_name, "librpm-%d.%d.so", major, minor); ++ h2 = dlopen (h2_name, RTLD_LAZY); ++ if (!h2) ++ { ++ fprintf (stderr, "dlopen (\"%s\"): %s\n", h2_name, dlerror ()); ++ fprintf (f, "%s\n", $LIBRPM_STRING); ++ return 0; ++ } ++ if (h2 != h) ++ { ++ fprintf (stderr, "dlopen of \"%s\" and \"%s\" are different.\n", ++ $LIBRPM_STRING, h2_name); ++ fprintf (f, "%s\n", $LIBRPM_STRING); ++ return 0; ++ } ++ /* Found the valid .so name with a specific version. */ ++ fprintf (f, "%s\n", h2_name); ++ return 0; ++ } ++ ++ ; ++ return 0; ++} ++_ACEOF ++rm -f conftest$ac_exeext ++if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 ++ (eval $ac_link) 2>&5 ++ ac_status=$? ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } && { ac_try='./conftest$ac_exeext' ++ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 ++ (eval $ac_try) 2>&5 ++ ac_status=$? ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); }; }; then ++ ++ DLOPEN_LIBRPM="`cat conftest.out`" ++ if test "x$DLOPEN_LIBRPM" != "x"; then ++ HAVE_DLOPEN_LIBRPM=true ++ echo "$as_me:$LINENO: result: $DLOPEN_LIBRPM" >&5 ++echo "${ECHO_T}$DLOPEN_LIBRPM" >&6 ++ fi ++ ++else ++ echo "$as_me: program exited with status $ac_status" >&5 ++echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++fi ++rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext ++fi ++ rm -f conftest.out ++ ++ ++ ++ if $HAVE_DLOPEN_LIBRPM; then ++ ++ echo "$as_me:$LINENO: checking rpm library API compatibility" >&5 ++echo $ECHO_N "checking rpm library API compatibility... $ECHO_C" >&6 ++ # The compilation requires -Werror to verify anything. ++ save_CFLAGS="$CFLAGS" ++ CFLAGS="$CFLAGS -Werror" ++ cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++ ++/* Duplicate here the declarations to verify they match "symfile.c". */ ++#include ++#include ++#include ++#include ++extern char * headerFormat(Header h, const char * fmt, errmsg_t * errmsg); ++extern int rpmReadConfigFiles(const char * file, const char * target); ++extern rpmdbMatchIterator rpmdbFreeIterator(rpmdbMatchIterator mi); ++extern Header rpmdbNextIterator(rpmdbMatchIterator mi); ++extern rpmts rpmtsCreate(void); ++extern rpmts rpmtsFree(rpmts ts); ++extern rpmdbMatchIterator rpmtsInitIterator(const rpmts ts, rpmTag rpmtag, ++ const void * keyp, size_t keylen); ++ ++int ++main () ++{ ++ ++ ; ++ return 0; ++} ++_ACEOF ++rm -f conftest.$ac_objext ++if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ++ (eval $ac_compile) 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } && ++ { ac_try='test -z "$ac_c_werror_flag" ++ || test ! -s conftest.err' ++ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 ++ (eval $ac_try) 2>&5 ++ ac_status=$? ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); }; } && ++ { ac_try='test -s conftest.$ac_objext' ++ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 ++ (eval $ac_try) 2>&5 ++ ac_status=$? ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); }; }; then ++ ++ LIBRPM_COMPAT=true ++ echo "$as_me:$LINENO: result: yes" >&5 ++echo "${ECHO_T}yes" >&6 ++ ++else ++ echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ ++ LIBRPM_COMPAT=false ++ echo "$as_me:$LINENO: result: no" >&5 ++echo "${ECHO_T}no" >&6 ++ ++fi ++rm -f conftest.err conftest.$ac_objext conftest.$ac_ext ++ CFLAGS="$save_CFLAGS" ++ ++ if ! $LIBRPM_COMPAT; then ++ HAVE_DLOPEN_LIBRPM=false ++ fi ++ fi ++ ++ if $HAVE_DLOPEN_LIBRPM; then ++ DLOPEN_LIBRPM_STRING='"'"$DLOPEN_LIBRPM"'"' ++ ++cat >>confdefs.h <<_ACEOF ++#define DLOPEN_LIBRPM $DLOPEN_LIBRPM_STRING ++_ACEOF ++ ++ ++cat >>confdefs.h <<\_ACEOF ++#define HAVE_LIBRPM 1 ++_ACEOF ++ ++ else ++ echo "$as_me:$LINENO: result: no" >&5 ++echo "${ECHO_T}no" >&6 ++ LIBS="$save_LIBS" ++ if $DLOPEN_REQUIRE; then ++ { { echo "$as_me:$LINENO: error: Specific name $LIBRPM was requested but it could not be opened." >&5 ++echo "$as_me: error: Specific name $LIBRPM was requested but it could not be opened." >&2;} ++ { (exit 1); exit 1; }; } ++ fi ++ ++ ++if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then ++ if test -n "$ac_tool_prefix"; then ++ # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. ++set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 ++echo "$as_me:$LINENO: checking for $ac_word" >&5 ++echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 ++if test "${ac_cv_path_PKG_CONFIG+set}" = set; then ++ echo $ECHO_N "(cached) $ECHO_C" >&6 ++else ++ case $PKG_CONFIG in ++ [\\/]* | ?:[\\/]*) ++ ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. ++ ;; ++ *) ++ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ++ ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" ++ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 ++ break 2 ++ fi ++done ++done ++ ++ ;; ++esac ++fi ++PKG_CONFIG=$ac_cv_path_PKG_CONFIG ++ ++if test -n "$PKG_CONFIG"; then ++ echo "$as_me:$LINENO: result: $PKG_CONFIG" >&5 ++echo "${ECHO_T}$PKG_CONFIG" >&6 ++else ++ echo "$as_me:$LINENO: result: no" >&5 ++echo "${ECHO_T}no" >&6 ++fi ++ ++fi ++if test -z "$ac_cv_path_PKG_CONFIG"; then ++ ac_pt_PKG_CONFIG=$PKG_CONFIG ++ # Extract the first word of "pkg-config", so it can be a program name with args. ++set dummy pkg-config; ac_word=$2 ++echo "$as_me:$LINENO: checking for $ac_word" >&5 ++echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 ++if test "${ac_cv_path_ac_pt_PKG_CONFIG+set}" = set; then ++ echo $ECHO_N "(cached) $ECHO_C" >&6 ++else ++ case $ac_pt_PKG_CONFIG in ++ [\\/]* | ?:[\\/]*) ++ ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. ++ ;; ++ *) ++ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ++ ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" ++ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 ++ break 2 ++ fi ++done ++done ++ ++ ;; ++esac ++fi ++ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG ++ ++if test -n "$ac_pt_PKG_CONFIG"; then ++ echo "$as_me:$LINENO: result: $ac_pt_PKG_CONFIG" >&5 ++echo "${ECHO_T}$ac_pt_PKG_CONFIG" >&6 ++else ++ echo "$as_me:$LINENO: result: no" >&5 ++echo "${ECHO_T}no" >&6 ++fi ++ ++ PKG_CONFIG=$ac_pt_PKG_CONFIG ++else ++ PKG_CONFIG="$ac_cv_path_PKG_CONFIG" ++fi ++ ++fi ++if test -n "$PKG_CONFIG"; then ++ _pkg_min_version=0.9.0 ++ echo "$as_me:$LINENO: checking pkg-config is at least version $_pkg_min_version" >&5 ++echo $ECHO_N "checking pkg-config is at least version $_pkg_min_version... $ECHO_C" >&6 ++ if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then ++ echo "$as_me:$LINENO: result: yes" >&5 ++echo "${ECHO_T}yes" >&6 ++ else ++ echo "$as_me:$LINENO: result: no" >&5 ++echo "${ECHO_T}no" >&6 ++ PKG_CONFIG="" ++ fi ++ ++fi ++ ++pkg_failed=no ++echo "$as_me:$LINENO: checking for RPM" >&5 ++echo $ECHO_N "checking for RPM... $ECHO_C" >&6 ++ ++if test -n "$RPM_CFLAGS"; then ++ pkg_cv_RPM_CFLAGS="$RPM_CFLAGS" ++ elif test -n "$PKG_CONFIG"; then ++ if test -n "$PKG_CONFIG" && \ ++ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"rpm\"") >&5 ++ ($PKG_CONFIG --exists --print-errors "rpm") 2>&5 ++ ac_status=$? ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); }; then ++ pkg_cv_RPM_CFLAGS=`$PKG_CONFIG --cflags "rpm" 2>/dev/null` ++else ++ pkg_failed=yes ++fi ++ else ++ pkg_failed=untried ++fi ++if test -n "$RPM_LIBS"; then ++ pkg_cv_RPM_LIBS="$RPM_LIBS" ++ elif test -n "$PKG_CONFIG"; then ++ if test -n "$PKG_CONFIG" && \ ++ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"rpm\"") >&5 ++ ($PKG_CONFIG --exists --print-errors "rpm") 2>&5 ++ ac_status=$? ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); }; then ++ pkg_cv_RPM_LIBS=`$PKG_CONFIG --libs "rpm" 2>/dev/null` ++else ++ pkg_failed=yes ++fi ++ else ++ pkg_failed=untried ++fi ++ ++ ++ ++if test $pkg_failed = yes; then ++ ++if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then ++ _pkg_short_errors_supported=yes ++else ++ _pkg_short_errors_supported=no ++fi ++ if test $_pkg_short_errors_supported = yes; then ++ RPM_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "rpm" 2>&1` ++ else ++ RPM_PKG_ERRORS=`$PKG_CONFIG --print-errors "rpm" 2>&1` ++ fi ++ # Put the nasty error message in config.log where it belongs ++ echo "$RPM_PKG_ERRORS" >&5 ++ ++ echo "$as_me:$LINENO: result: no" >&5 ++echo "${ECHO_T}no" >&6 ++ HAVE_LIBRPM=false ++elif test $pkg_failed = untried; then ++ HAVE_LIBRPM=false ++else ++ RPM_CFLAGS=$pkg_cv_RPM_CFLAGS ++ RPM_LIBS=$pkg_cv_RPM_LIBS ++ echo "$as_me:$LINENO: result: yes" >&5 ++echo "${ECHO_T}yes" >&6 ++ HAVE_LIBRPM=true ++fi ++ ++ if $HAVE_LIBRPM; then ++ ++ echo "$as_me:$LINENO: checking rpm library API compatibility" >&5 ++echo $ECHO_N "checking rpm library API compatibility... $ECHO_C" >&6 ++ # The compilation requires -Werror to verify anything. ++ save_CFLAGS="$CFLAGS" ++ CFLAGS="$CFLAGS -Werror" ++ cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++ ++/* Duplicate here the declarations to verify they match "symfile.c". */ ++#include ++#include ++#include ++#include ++extern char * headerFormat(Header h, const char * fmt, errmsg_t * errmsg); ++extern int rpmReadConfigFiles(const char * file, const char * target); ++extern rpmdbMatchIterator rpmdbFreeIterator(rpmdbMatchIterator mi); ++extern Header rpmdbNextIterator(rpmdbMatchIterator mi); ++extern rpmts rpmtsCreate(void); ++extern rpmts rpmtsFree(rpmts ts); ++extern rpmdbMatchIterator rpmtsInitIterator(const rpmts ts, rpmTag rpmtag, ++ const void * keyp, size_t keylen); ++ ++int ++main () ++{ ++ ++ ; ++ return 0; ++} ++_ACEOF ++rm -f conftest.$ac_objext ++if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ++ (eval $ac_compile) 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } && ++ { ac_try='test -z "$ac_c_werror_flag" ++ || test ! -s conftest.err' ++ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 ++ (eval $ac_try) 2>&5 ++ ac_status=$? ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); }; } && ++ { ac_try='test -s conftest.$ac_objext' ++ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 ++ (eval $ac_try) 2>&5 ++ ac_status=$? ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); }; }; then ++ ++ LIBRPM_COMPAT=true ++ echo "$as_me:$LINENO: result: yes" >&5 ++echo "${ECHO_T}yes" >&6 ++ ++else ++ echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ ++ LIBRPM_COMPAT=false ++ echo "$as_me:$LINENO: result: no" >&5 ++echo "${ECHO_T}no" >&6 ++ ++fi ++rm -f conftest.err conftest.$ac_objext conftest.$ac_ext ++ CFLAGS="$save_CFLAGS" ++ ++ if ! $LIBRPM_COMPAT; then ++ HAVE_LIBRPM=false ++ RPM_PKG_ERRORS="Found $LIBRPM API is incompatibile with this GDB" ++ fi ++ fi ++ ++ if $HAVE_LIBRPM; then ++ ++cat >>confdefs.h <<\_ACEOF ++#define HAVE_LIBRPM 1 ++_ACEOF ++ ++ CFLAGS="$CFLAGS $RPM_CFLAGS" ++ LIBS="$LIBS $RPM_LIBS" ++ else ++ if $RPM_REQUIRE; then ++ { { echo "$as_me:$LINENO: error: $RPM_PKG_ERRORS" >&5 ++echo "$as_me: error: $RPM_PKG_ERRORS" >&2;} ++ { (exit 1); exit 1; }; } ++ else ++ { echo "$as_me:$LINENO: WARNING: $RPM_PKG_ERRORS" >&5 ++echo "$as_me: WARNING: $RPM_PKG_ERRORS" >&2;} ++ fi ++ fi ++ fi ++fi ++ + + + +@@ -8623,7 +9181,6 @@ done + # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" + # OS/2's system install, which has a completely different semantic + # ./install, which can be erroneously created by make from ./install.sh. +-# Reject install programs that cannot install multiple files. + echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 + echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6 + if test -z "$INSTALL"; then +@@ -8657,18 +9214,8 @@ case $as_dir/ in + # program-specific install script used by HP pwplus--don't use. + : + else +- rm -rf conftest.one conftest.two conftest.dir +- echo one > conftest.one +- echo two > conftest.two +- mkdir conftest.dir +- if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && +- test -s conftest.one && test -s conftest.two && +- test -s conftest.dir/conftest.one && +- test -s conftest.dir/conftest.two +- then +- ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" +- break 3 +- fi ++ ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" ++ break 3 + fi + fi + done +@@ -8677,16 +9224,15 @@ case $as_dir/ in + esac + done + +-rm -rf conftest.one conftest.two conftest.dir + + fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else +- # As a last resort, use the slow shell script. Don't cache a +- # value for INSTALL within a source directory, because that will ++ # As a last resort, use the slow shell script. We don't cache a ++ # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is +- # removed, or if the value is a relative name. ++ # removed, or if the path is relative. + INSTALL=$ac_install_sh + fi + fi +@@ -22270,6 +22816,10 @@ s,@am__fastdepCC_TRUE@,$am__fastdepCC_TR + s,@am__fastdepCC_FALSE@,$am__fastdepCC_FALSE,;t t + s,@GDB_DATADIR_PATH@,$GDB_DATADIR_PATH,;t t + s,@pythondir@,$pythondir,;t t ++s,@PKG_CONFIG@,$PKG_CONFIG,;t t ++s,@ac_pt_PKG_CONFIG@,$ac_pt_PKG_CONFIG,;t t ++s,@RPM_CFLAGS@,$RPM_CFLAGS,;t t ++s,@RPM_LIBS@,$RPM_LIBS,;t t + s,@subdirs@,$subdirs,;t t + s,@TARGET_OBS@,$TARGET_OBS,;t t + s,@PKGVERSION@,$PKGVERSION,;t t +Index: gdb-6.8.50.20090302/gdb/configure.ac +=================================================================== +--- gdb-6.8.50.20090302.orig/gdb/configure.ac 2009-03-07 17:13:33.000000000 +0100 ++++ gdb-6.8.50.20090302/gdb/configure.ac 2009-03-07 17:25:06.000000000 +0100 +@@ -162,6 +162,199 @@ else + fi + AC_SUBST(pythondir) + ++# Integration with rpm library to support missing debuginfo suggestions. ++# --without-rpm: Disable any rpm support. ++# --with-rpm=libname.so: Try to dynamically open `libname.so' during runtime. ++# Even with runtime missing `libname.so' GDB will still other run correctly. ++# Missing `libname.so' during ./configure will abort the configuration. ++# --with-rpm=librpm.so: Like `--with-rpm=libname.so' but try to find specific ++# minor version first such as `librpm-4.6.so' as minor version differences ++# mean API+ABI incompatibility. If the specific match versioned library name ++# could not be found still open dynamically at least `librpm.so'. ++# --with-rpm: Like `--with-rpm=librpm.so' but if any of its detection fails try ++# to find librpm for compilation-time linking by pkg-config. GDB binary will ++# be probably linked with the version specific library (as `librpm-4.6.so'). ++# Failure to find librpm by pkg-config will abort the configuration. ++# (default) --with-rpm=auto: Like `--with-rpm=librpm.so' but if even pkg-config ++# cannot find librpm use to the rpmless compilation (like `--without-rpm'). ++ ++AC_ARG_WITH([rpm], ++ [AS_HELP_STRING([--with-rpm], ++ [query rpm database for missing debuginfos [yes/no, def. auto=librpm.so]])], [], [with_rpm="auto"]) ++ ++m4_pattern_allow([^AC_MSG_ERROR$]) ++m4_pattern_allow([^AC_MSG_WARN$]) ++if test "x$with_rpm" != "xno"; then ++ if test "x$with_rpm" = "xyes"; then ++ LIBRPM="librpm.so" ++ RPM_REQUIRE=true ++ DLOPEN_REQUIRE=false ++ elif test "x$with_rpm" = "xauto"; then ++ LIBRPM="librpm.so" ++ RPM_REQUIRE=false ++ DLOPEN_REQUIRE=false ++ else ++ LIBRPM="$with_rpm" ++ RPM_REQUIRE=true ++ DLOPEN_REQUIRE=true ++ fi ++ LIBRPM_STRING='"'"$LIBRPM"'"' ++ ++ AC_MSG_CHECKING([specific librpm version]) ++ HAVE_DLOPEN_LIBRPM=false ++ save_LIBS="$LIBS" ++ LIBS="$LIBS -ldl" ++ AC_RUN_IFELSE(AC_LANG_PROGRAM([[ ++#include ++#include ++#include ++ ]], [[ ++ void *h; ++ const char *const *rpmverp; ++ FILE *f; ++ ++ f = fopen ("conftest.out", "w"); ++ if (!f) ++ { ++ fprintf (stderr, "Cannot write \"%s\": %s\n", "conftest.out", ++ strerror (errno)); ++ return 1; ++ } ++ h = dlopen ($LIBRPM_STRING, RTLD_LAZY); ++ if (!h) ++ { ++ fprintf (stderr, "dlopen (\"%s\"): %s\n", $LIBRPM_STRING, dlerror ()); ++ return 1; ++ } ++ rpmverp = dlsym (h, "RPMVERSION"); ++ if (!rpmverp) ++ { ++ fprintf (stderr, "dlsym (\"RPMVERSION\"): %s\n", dlerror ()); ++ return 1; ++ } ++ fprintf (stderr, "RPMVERSION is: \""); ++ fprintf (stderr, "%s\"\n", *rpmverp); ++ ++ /* Try to find the specific librpm version only for "librpm.so" as we do ++ not know how to assemble the version string otherwise. */ ++ ++ if (strcmp ("librpm.so", $LIBRPM_STRING) != 0) ++ { ++ fprintf (f, "%s\n", $LIBRPM_STRING); ++ return 0; ++ } ++ else ++ { ++ char *h2_name; ++ void *h2; ++ int major, minor; ++ ++ if (sscanf (*rpmverp, "%d.%d", &major, &minor) != 2) ++ { ++ fprintf (stderr, "Unable to parse RPMVERSION.\n"); ++ fprintf (f, "%s\n", $LIBRPM_STRING); ++ return 0; ++ } ++ /* Avoid the square brackets by malloc. */ ++ h2_name = malloc (64); ++ sprintf (h2_name, "librpm-%d.%d.so", major, minor); ++ h2 = dlopen (h2_name, RTLD_LAZY); ++ if (!h2) ++ { ++ fprintf (stderr, "dlopen (\"%s\"): %s\n", h2_name, dlerror ()); ++ fprintf (f, "%s\n", $LIBRPM_STRING); ++ return 0; ++ } ++ if (h2 != h) ++ { ++ fprintf (stderr, "dlopen of \"%s\" and \"%s\" are different.\n", ++ $LIBRPM_STRING, h2_name); ++ fprintf (f, "%s\n", $LIBRPM_STRING); ++ return 0; ++ } ++ /* Found the valid .so name with a specific version. */ ++ fprintf (f, "%s\n", h2_name); ++ return 0; ++ } ++ ]]), [ ++ DLOPEN_LIBRPM="`cat conftest.out`" ++ if test "x$DLOPEN_LIBRPM" != "x"; then ++ HAVE_DLOPEN_LIBRPM=true ++ AC_MSG_RESULT($DLOPEN_LIBRPM) ++ fi ++ ]) ++ rm -f conftest.out ++ ++ m4_define([CHECK_LIBRPM_COMPAT], [ ++ AC_MSG_CHECKING([rpm library API compatibility]) ++ # The compilation requires -Werror to verify anything. ++ save_CFLAGS="$CFLAGS" ++ CFLAGS="$CFLAGS -Werror" ++ AC_COMPILE_IFELSE(AC_LANG_PROGRAM([[ ++/* Duplicate here the declarations to verify they match "symfile.c". */ ++#include ++#include ++#include ++#include ++extern char * headerFormat(Header h, const char * fmt, errmsg_t * errmsg); ++extern int rpmReadConfigFiles(const char * file, const char * target); ++extern rpmdbMatchIterator rpmdbFreeIterator(rpmdbMatchIterator mi); ++extern Header rpmdbNextIterator(rpmdbMatchIterator mi); ++extern rpmts rpmtsCreate(void); ++extern rpmts rpmtsFree(rpmts ts); ++extern rpmdbMatchIterator rpmtsInitIterator(const rpmts ts, rpmTag rpmtag, ++ const void * keyp, size_t keylen); ++ ]]), [ ++ LIBRPM_COMPAT=true ++ AC_MSG_RESULT(yes) ++ ], [ ++ LIBRPM_COMPAT=false ++ AC_MSG_RESULT(no) ++ ]) ++ CFLAGS="$save_CFLAGS" ++ ]) ++ ++ if $HAVE_DLOPEN_LIBRPM; then ++ CHECK_LIBRPM_COMPAT ++ if ! $LIBRPM_COMPAT; then ++ HAVE_DLOPEN_LIBRPM=false ++ fi ++ fi ++ ++ if $HAVE_DLOPEN_LIBRPM; then ++ DLOPEN_LIBRPM_STRING='"'"$DLOPEN_LIBRPM"'"' ++ AC_DEFINE_UNQUOTED(DLOPEN_LIBRPM, $DLOPEN_LIBRPM_STRING, [librpm version specific library name to dlopen.]) ++ AC_DEFINE(HAVE_LIBRPM, 1, [Define if librpm library is being used.]) ++ else ++ AC_MSG_RESULT(no) ++ LIBS="$save_LIBS" ++ if $DLOPEN_REQUIRE; then ++ AC_MSG_ERROR([Specific name $LIBRPM was requested but it could not be opened.]) ++ fi ++ PKG_CHECK_MODULES(RPM, rpm, [HAVE_LIBRPM=true], [HAVE_LIBRPM=false]) ++ ++ if $HAVE_LIBRPM; then ++ CHECK_LIBRPM_COMPAT ++ if ! $LIBRPM_COMPAT; then ++ HAVE_LIBRPM=false ++ RPM_PKG_ERRORS="Found $LIBRPM API is incompatibile with this GDB" ++ fi ++ fi ++ ++ if $HAVE_LIBRPM; then ++ AC_DEFINE(HAVE_LIBRPM, 1, [Define if librpm library is being used.]) ++ CFLAGS="$CFLAGS $RPM_CFLAGS" ++ LIBS="$LIBS $RPM_LIBS" ++ else ++ if $RPM_REQUIRE; then ++ AC_MSG_ERROR($RPM_PKG_ERRORS) ++ else ++ AC_MSG_WARN($RPM_PKG_ERRORS) ++ fi ++ fi ++ fi ++fi ++ + + AC_CONFIG_SUBDIRS(doc testsuite) + diff --git a/gdb-6.6-buildid-locate.patch b/gdb-6.6-buildid-locate.patch new file mode 100644 index 0000000..bc440b3 --- /dev/null +++ b/gdb-6.6-buildid-locate.patch @@ -0,0 +1,987 @@ +Index: gdb-6.8.50.20090302/gdb/corelow.c +=================================================================== +--- gdb-6.8.50.20090302.orig/gdb/corelow.c 2009-02-23 01:03:48.000000000 +0100 ++++ gdb-6.8.50.20090302/gdb/corelow.c 2009-03-07 17:04:57.000000000 +0100 +@@ -45,6 +45,10 @@ + #include "exceptions.h" + #include "solib.h" + #include "filenames.h" ++#include "auxv.h" ++#include "elf/common.h" ++#include "objfiles.h" ++#include "gdbcmd.h" + + + #ifndef O_LARGEFILE +@@ -267,6 +271,56 @@ add_to_thread_list (bfd *abfd, asection + inferior_ptid = ptid; /* Yes, make it current */ + } + ++static int build_id_core_loads = 1; ++ ++static void ++build_id_locate_exec (int from_tty) ++{ ++ CORE_ADDR at_entry; ++ struct build_id *build_id; ++ char *exec_filename, *debug_filename; ++ char *build_id_filename; ++ ++ if (exec_bfd != NULL) ++ return; ++ ++ if (target_auxv_search (¤t_target, AT_ENTRY, &at_entry) <= 0) ++ return; ++ ++ build_id = build_id_addr_get (at_entry); ++ if (build_id == NULL) ++ return; ++ ++ exec_filename = build_id_to_filename (build_id, &build_id_filename, 0); ++ if (exec_filename != NULL) ++ exec_file_attach (exec_filename, from_tty); ++ else ++ debug_print_missing (_("the main executable file"), build_id_filename); ++ xfree (build_id_filename); ++ ++ /* `.note.gnu.build-id' section exists even for files without a separate ++ debuginfo. */ ++ debug_filename = build_id_to_filename (build_id, &build_id_filename, 1); ++ if (debug_filename != NULL) ++ { ++ symbol_file_add_main (debug_filename, from_tty); ++ xfree (debug_filename); ++ } ++ else ++ { ++ if (exec_filename != NULL) ++ symbol_file_add_main (exec_filename, from_tty); ++ /* For EXEC_FILENAME NULL we were already complaining above. */ ++ if (symfile_objfile == NULL && exec_filename != NULL) ++ debug_print_missing (exec_filename, build_id_filename); ++ } ++ xfree (build_id_filename); ++ ++ xfree (exec_filename); ++ ++ /* No automatic SOLIB_ADD as the libraries would get read twice. */ ++} ++ + /* This routine opens and sets up the core file bfd. */ + + static void +@@ -363,6 +417,12 @@ core_open (char *filename, int from_tty) + push_target (&core_ops); + discard_cleanups (old_chain); + ++ /* Find the build_id identifiers. If it gets executed after ++ POST_CREATE_INFERIOR we would clash with asking to discard the already ++ loaded VDSO symbols. */ ++ if (build_id_core_loads != 0) ++ build_id_locate_exec (from_tty); ++ + add_inferior_silent (corelow_pid); + + /* Do this before acknowledging the inferior, so if +@@ -751,4 +811,11 @@ _initialize_corelow (void) + init_core_ops (); + + add_target (&core_ops); ++ ++ add_setshow_boolean_cmd ("build-id-core-loads", class_files, ++ &build_id_core_loads, _("\ ++Set whether CORE-FILE loads the build-id associated files automatically."), _("\ ++Show whether CORE-FILE loads the build-id associated files automatically.."), ++ NULL, NULL, NULL, ++ &setlist, &showlist); + } +Index: gdb-6.8.50.20090302/gdb/doc/gdb.texinfo +=================================================================== +--- gdb-6.8.50.20090302.orig/gdb/doc/gdb.texinfo 2009-03-07 17:04:56.000000000 +0100 ++++ gdb-6.8.50.20090302/gdb/doc/gdb.texinfo 2009-03-07 17:04:57.000000000 +0100 +@@ -13294,6 +13294,27 @@ information files. + + @end table + ++You can also adjust the current verbosity of the @dfn{build id} locating. ++ ++@table @code ++ ++@kindex set build-id-verbose ++@item set build-id-verbose 0 ++No additional messages are printed. ++ ++@item set build-id-verbose 1 ++Missing separate debug filenames are printed. ++ ++@item set build-id-verbose 2 ++Missing separate debug filenames are printed and also all the parsing of the ++binaries to find their @dfn{build id} content is printed. ++ ++@kindex show build-id-verbose ++@item show build-id-verbose ++Show the current verbosity value for the @dfn{build id} content locating. ++ ++@end table ++ + @cindex @code{.gnu_debuglink} sections + @cindex debug link sections + A debug link is a special section of the executable file named +Index: gdb-6.8.50.20090302/gdb/solib-svr4.c +=================================================================== +--- gdb-6.8.50.20090302.orig/gdb/solib-svr4.c 2009-03-07 17:04:52.000000000 +0100 ++++ gdb-6.8.50.20090302/gdb/solib-svr4.c 2009-03-07 17:04:57.000000000 +0100 +@@ -1000,9 +1000,33 @@ 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); ++ struct build_id *build_id; ++ ++ strncpy (new->so_original_name, buffer, SO_NAME_MAX_PATH_SIZE - 1); ++ new->so_original_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0'; ++ /* May get overwritten below. */ ++ strcpy (new->so_name, new->so_original_name); ++ ++ build_id = build_id_addr_get (LM_DYNAMIC_FROM_LINK_MAP (new)); ++ if (build_id != NULL) ++ { ++ char *name, *build_id_filename; ++ ++ /* Missing the build-id matching separate debug info file ++ would be handled while SO_NAME gets loaded. */ ++ name = build_id_to_filename (build_id, &build_id_filename, 0); ++ if (name != NULL) ++ { ++ strncpy (new->so_name, name, SO_NAME_MAX_PATH_SIZE - 1); ++ new->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0'; ++ xfree (name); ++ } ++ else ++ debug_print_missing (new->so_name, build_id_filename); ++ ++ xfree (build_id_filename); ++ xfree (build_id); ++ } + } + xfree (buffer); + +Index: gdb-6.8.50.20090302/gdb/symfile.c +=================================================================== +--- gdb-6.8.50.20090302.orig/gdb/symfile.c 2009-03-07 17:04:53.000000000 +0100 ++++ gdb-6.8.50.20090302/gdb/symfile.c 2009-03-07 17:22:21.000000000 +0100 +@@ -54,6 +54,7 @@ + #include "elf-bfd.h" + #include "solib.h" + #include "remote.h" ++#include "libbfd.h" + + #include + #include +@@ -1185,16 +1186,65 @@ symbol_file_clear (int from_tty) + printf_unfiltered (_("No symbol file now.\n")); + } + ++/* Locate NT_GNU_BUILD_ID and return its matching debug filename. ++ FIXME: NOTE decoding should be unified with the BFD core notes decoding. */ ++ ++#define BUILD_ID_VERBOSE_NONE 0 ++#define BUILD_ID_VERBOSE_FILENAMES 1 ++#define BUILD_ID_VERBOSE_BINARY_PARSE 2 ++static int build_id_verbose = BUILD_ID_VERBOSE_FILENAMES; ++static void ++show_build_id_verbose (struct ui_file *file, int from_tty, ++ struct cmd_list_element *c, const char *value) ++{ ++ fprintf_filtered (file, _("Verbosity level of the build-id locator is %s.\n"), ++ value); ++} ++ + struct build_id + { + size_t size; + gdb_byte data[1]; + }; + +-/* Locate NT_GNU_BUILD_ID from ABFD and return its content. */ ++struct build_id * ++build_id_buf_get (bfd *templ, gdb_byte *buf, bfd_size_type size) ++{ ++ bfd_byte *p; ++ ++ p = buf; ++ while (p < buf + size) ++ { ++ /* FIXME: bad alignment assumption. */ ++ Elf_External_Note *xnp = (Elf_External_Note *) p; ++ size_t namesz = H_GET_32 (templ, xnp->namesz); ++ size_t descsz = H_GET_32 (templ, xnp->descsz); ++ bfd_byte *descdata = xnp->name + BFD_ALIGN (namesz, 4); ++ ++ if (H_GET_32 (templ, xnp->type) == NT_GNU_BUILD_ID ++ && namesz == sizeof "GNU" ++ && memcmp (xnp->name, "GNU", sizeof "GNU") == 0) ++ { ++ size_t size = descsz; ++ gdb_byte *data = (void *) descdata; ++ struct build_id *retval; ++ ++ retval = xmalloc (sizeof *retval - 1 + size); ++ retval->size = size; ++ memcpy (retval->data, data, size); ++ ++ return retval; ++ } ++ p = descdata + BFD_ALIGN (descsz, 4); ++ } ++ return NULL; ++} ++ ++/* Separate debuginfo files have corrupted PHDR but SHDR is correct there. ++ Locate NT_GNU_BUILD_ID from ABFD and return its content. */ + + static struct build_id * +-build_id_bfd_get (bfd *abfd) ++build_id_bfd_shdr_get (bfd *abfd) + { + struct build_id *retval; + +@@ -1210,6 +1260,348 @@ build_id_bfd_get (bfd *abfd) + return retval; + } + ++/* Core files may have missing (corrupt) SHDR but PDHR is correct there. ++ bfd_elf_bfd_from_remote_memory () has too much overhead by ++ allocating/reading all the available ELF PT_LOADs. */ ++ ++static struct build_id * ++build_id_phdr_get (bfd *templ, bfd_vma loadbase, unsigned e_phnum, ++ Elf_Internal_Phdr *i_phdr) ++{ ++ int i; ++ struct build_id *retval = NULL; ++ ++ for (i = 0; i < e_phnum; i++) ++ if (i_phdr[i].p_type == PT_NOTE && i_phdr[i].p_filesz > 0) ++ { ++ Elf_Internal_Phdr *hdr = &i_phdr[i]; ++ gdb_byte *buf; ++ int err; ++ ++ buf = xmalloc (hdr->p_filesz); ++ err = target_read_memory (loadbase + i_phdr[i].p_vaddr, buf, ++ hdr->p_filesz); ++ if (err == 0) ++ retval = build_id_buf_get (templ, buf, hdr->p_filesz); ++ else ++ retval = NULL; ++ xfree (buf); ++ if (retval != NULL) ++ break; ++ } ++ return retval; ++} ++ ++/* First we validate the file by reading in the ELF header and checking ++ the magic number. */ ++ ++static inline bfd_boolean ++elf_file_p (Elf64_External_Ehdr *x_ehdrp64) ++{ ++ gdb_assert (sizeof (Elf64_External_Ehdr) >= sizeof (Elf32_External_Ehdr)); ++ gdb_assert (offsetof (Elf64_External_Ehdr, e_ident) ++ == offsetof (Elf32_External_Ehdr, e_ident)); ++ gdb_assert (sizeof (((Elf64_External_Ehdr *) 0)->e_ident) ++ == sizeof (((Elf32_External_Ehdr *) 0)->e_ident)); ++ ++ return ((x_ehdrp64->e_ident[EI_MAG0] == ELFMAG0) ++ && (x_ehdrp64->e_ident[EI_MAG1] == ELFMAG1) ++ && (x_ehdrp64->e_ident[EI_MAG2] == ELFMAG2) ++ && (x_ehdrp64->e_ident[EI_MAG3] == ELFMAG3)); ++} ++ ++/* Translate an ELF file header in external format into an ELF file header in ++ internal format. */ ++ ++#define H_GET_WORD(bfd, ptr) (is64 ? H_GET_64 (bfd, (ptr)) \ ++ : H_GET_32 (bfd, (ptr))) ++#define H_GET_SIGNED_WORD(bfd, ptr) (is64 ? H_GET_S64 (bfd, (ptr)) \ ++ : H_GET_S32 (bfd, (ptr))) ++ ++static void ++elf_swap_ehdr_in (bfd *abfd, ++ const Elf64_External_Ehdr *src64, ++ Elf_Internal_Ehdr *dst) ++{ ++ int is64 = bfd_get_arch_size (abfd) == 64; ++#define SRC(field) (is64 ? src64->field \ ++ : ((const Elf32_External_Ehdr *) src64)->field) ++ ++ int signed_vma = get_elf_backend_data (abfd)->sign_extend_vma; ++ memcpy (dst->e_ident, SRC (e_ident), EI_NIDENT); ++ dst->e_type = H_GET_16 (abfd, SRC (e_type)); ++ dst->e_machine = H_GET_16 (abfd, SRC (e_machine)); ++ dst->e_version = H_GET_32 (abfd, SRC (e_version)); ++ if (signed_vma) ++ dst->e_entry = H_GET_SIGNED_WORD (abfd, SRC (e_entry)); ++ else ++ dst->e_entry = H_GET_WORD (abfd, SRC (e_entry)); ++ dst->e_phoff = H_GET_WORD (abfd, SRC (e_phoff)); ++ dst->e_shoff = H_GET_WORD (abfd, SRC (e_shoff)); ++ dst->e_flags = H_GET_32 (abfd, SRC (e_flags)); ++ dst->e_ehsize = H_GET_16 (abfd, SRC (e_ehsize)); ++ dst->e_phentsize = H_GET_16 (abfd, SRC (e_phentsize)); ++ dst->e_phnum = H_GET_16 (abfd, SRC (e_phnum)); ++ dst->e_shentsize = H_GET_16 (abfd, SRC (e_shentsize)); ++ dst->e_shnum = H_GET_16 (abfd, SRC (e_shnum)); ++ dst->e_shstrndx = H_GET_16 (abfd, SRC (e_shstrndx)); ++ ++#undef SRC ++} ++ ++/* Translate an ELF program header table entry in external format into an ++ ELF program header table entry in internal format. */ ++ ++void ++elf_swap_phdr_in (bfd *abfd, ++ const Elf64_External_Phdr *src64, ++ Elf_Internal_Phdr *dst) ++{ ++ int is64 = bfd_get_arch_size (abfd) == 64; ++#define SRC(field) (is64 ? src64->field \ ++ : ((const Elf32_External_Phdr *) src64)->field) ++ ++ int signed_vma = get_elf_backend_data (abfd)->sign_extend_vma; ++ ++ dst->p_type = H_GET_32 (abfd, SRC (p_type)); ++ dst->p_flags = H_GET_32 (abfd, SRC (p_flags)); ++ dst->p_offset = H_GET_WORD (abfd, SRC (p_offset)); ++ if (signed_vma) ++ { ++ dst->p_vaddr = H_GET_SIGNED_WORD (abfd, SRC (p_vaddr)); ++ dst->p_paddr = H_GET_SIGNED_WORD (abfd, SRC (p_paddr)); ++ } ++ else ++ { ++ dst->p_vaddr = H_GET_WORD (abfd, SRC (p_vaddr)); ++ dst->p_paddr = H_GET_WORD (abfd, SRC (p_paddr)); ++ } ++ dst->p_filesz = H_GET_WORD (abfd, SRC (p_filesz)); ++ dst->p_memsz = H_GET_WORD (abfd, SRC (p_memsz)); ++ dst->p_align = H_GET_WORD (abfd, SRC (p_align)); ++ ++#undef SRC ++} ++ ++#undef H_GET_SIGNED_WORD ++#undef H_GET_WORD ++ ++static Elf_Internal_Phdr * ++elf_get_phdr (bfd *templ, bfd_vma ehdr_vma, unsigned *e_phnum_pointer, ++ bfd_vma *loadbase_pointer) ++{ ++ /* sizeof (Elf64_External_Ehdr) >= sizeof (Elf32_External_Ehdr) */ ++ Elf64_External_Ehdr x_ehdr64; /* Elf file header, external form */ ++ Elf_Internal_Ehdr i_ehdr; /* Elf file header, internal form */ ++ bfd_size_type x_phdrs_size; ++ gdb_byte *x_phdrs_ptr; ++ Elf_Internal_Phdr *i_phdrs; ++ int err; ++ unsigned int i; ++ bfd_vma loadbase; ++ int loadbase_set; ++ ++ gdb_assert (templ != NULL); ++ gdb_assert (sizeof (Elf64_External_Ehdr) >= sizeof (Elf32_External_Ehdr)); ++ ++ /* Read in the ELF header in external format. */ ++ err = target_read_memory (ehdr_vma, (bfd_byte *) &x_ehdr64, sizeof x_ehdr64); ++ if (err) ++ { ++ if (build_id_verbose >= BUILD_ID_VERBOSE_BINARY_PARSE) ++ warning (_("build-id: Error reading ELF header at address 0x%lx"), ++ (unsigned long) ehdr_vma); ++ return NULL; ++ } ++ ++ /* Now check to see if we have a valid ELF file, and one that BFD can ++ make use of. The magic number must match, the address size ('class') ++ and byte-swapping must match our XVEC entry. */ ++ ++ if (! elf_file_p (&x_ehdr64) ++ || x_ehdr64.e_ident[EI_VERSION] != EV_CURRENT ++ || !((bfd_get_arch_size (templ) == 64 ++ && x_ehdr64.e_ident[EI_CLASS] == ELFCLASS64) ++ || (bfd_get_arch_size (templ) == 32 ++ && x_ehdr64.e_ident[EI_CLASS] == ELFCLASS32))) ++ { ++ if (build_id_verbose >= BUILD_ID_VERBOSE_BINARY_PARSE) ++ warning (_("build-id: Unrecognized ELF header at address 0x%lx"), ++ (unsigned long) ehdr_vma); ++ return NULL; ++ } ++ ++ /* Check that file's byte order matches xvec's */ ++ switch (x_ehdr64.e_ident[EI_DATA]) ++ { ++ case ELFDATA2MSB: /* Big-endian */ ++ if (! bfd_header_big_endian (templ)) ++ { ++ if (build_id_verbose >= BUILD_ID_VERBOSE_BINARY_PARSE) ++ warning (_("build-id: Unrecognized " ++ "big-endian ELF header at address 0x%lx"), ++ (unsigned long) ehdr_vma); ++ return NULL; ++ } ++ break; ++ case ELFDATA2LSB: /* Little-endian */ ++ if (! bfd_header_little_endian (templ)) ++ { ++ if (build_id_verbose >= BUILD_ID_VERBOSE_BINARY_PARSE) ++ warning (_("build-id: Unrecognized " ++ "little-endian ELF header at address 0x%lx"), ++ (unsigned long) ehdr_vma); ++ return NULL; ++ } ++ break; ++ case ELFDATANONE: /* No data encoding specified */ ++ default: /* Unknown data encoding specified */ ++ if (build_id_verbose >= BUILD_ID_VERBOSE_BINARY_PARSE) ++ warning (_("build-id: Unrecognized " ++ "ELF header endianity at address 0x%lx"), ++ (unsigned long) ehdr_vma); ++ return NULL; ++ } ++ ++ elf_swap_ehdr_in (templ, &x_ehdr64, &i_ehdr); ++ ++ /* The file header tells where to find the program headers. ++ These are what we use to actually choose what to read. */ ++ ++ if (i_ehdr.e_phentsize != (bfd_get_arch_size (templ) == 64 ++ ? sizeof (Elf64_External_Phdr) ++ : sizeof (Elf32_External_Phdr)) ++ || i_ehdr.e_phnum == 0) ++ { ++ if (build_id_verbose >= BUILD_ID_VERBOSE_BINARY_PARSE) ++ warning (_("build-id: Invalid ELF program headers from the ELF header " ++ "at address 0x%lx"), (unsigned long) ehdr_vma); ++ return NULL; ++ } ++ ++ x_phdrs_size = (bfd_get_arch_size (templ) == 64 ? sizeof (Elf64_External_Phdr) ++ : sizeof (Elf32_External_Phdr)); ++ ++ i_phdrs = xmalloc (i_ehdr.e_phnum * (sizeof *i_phdrs + x_phdrs_size)); ++ x_phdrs_ptr = (void *) &i_phdrs[i_ehdr.e_phnum]; ++ err = target_read_memory (ehdr_vma + i_ehdr.e_phoff, (bfd_byte *) x_phdrs_ptr, ++ i_ehdr.e_phnum * x_phdrs_size); ++ if (err) ++ { ++ free (i_phdrs); ++ if (build_id_verbose >= BUILD_ID_VERBOSE_BINARY_PARSE) ++ warning (_("build-id: Error reading " ++ "ELF program headers at address 0x%lx"), ++ (unsigned long) (ehdr_vma + i_ehdr.e_phoff)); ++ return NULL; ++ } ++ ++ loadbase = ehdr_vma; ++ loadbase_set = 0; ++ for (i = 0; i < i_ehdr.e_phnum; ++i) ++ { ++ elf_swap_phdr_in (templ, (Elf64_External_Phdr *) ++ (x_phdrs_ptr + i * x_phdrs_size), &i_phdrs[i]); ++ /* IA-64 vDSO may have two mappings for one segment, where one mapping ++ is executable only, and one is read only. We must not use the ++ executable one (PF_R is the first one, PF_X the second one). */ ++ if (i_phdrs[i].p_type == PT_LOAD && (i_phdrs[i].p_flags & PF_R)) ++ { ++ /* Only the first PT_LOAD segment indicates the file bias. ++ Next segments may have P_VADDR arbitrarily higher. ++ If the first segment has P_VADDR zero any next segment must not ++ confuse us, the first one sets LOADBASE certainly enough. */ ++ if (!loadbase_set && i_phdrs[i].p_offset == 0) ++ { ++ loadbase = ehdr_vma - i_phdrs[i].p_vaddr; ++ loadbase_set = 1; ++ } ++ } ++ } ++ ++ if (build_id_verbose >= BUILD_ID_VERBOSE_BINARY_PARSE) ++ warning (_("build-id: Found ELF header at address 0x%lx, loadbase 0x%lx"), ++ (unsigned long) ehdr_vma, (unsigned long) loadbase); ++ ++ *e_phnum_pointer = i_ehdr.e_phnum; ++ *loadbase_pointer = loadbase; ++ return i_phdrs; ++} ++ ++/* BUILD_ID_ADDR_GET gets ADDR located somewhere in the object. ++ Find the first section before ADDR containing an ELF header. ++ We rely on the fact the sections from multiple files do not mix. ++ FIXME: We should check ADDR is contained _inside_ the section with possibly ++ missing content (P_FILESZ < P_MEMSZ). These omitted sections are currently ++ hidden by _BFD_ELF_MAKE_SECTION_FROM_PHDR. */ ++ ++static CORE_ADDR build_id_addr; ++struct build_id_addr_sect ++ { ++ struct build_id_addr_sect *next; ++ asection *sect; ++ }; ++static struct build_id_addr_sect *build_id_addr_sect; ++ ++static void build_id_addr_candidate (bfd *abfd, asection *sect, void *obj) ++{ ++ if (build_id_addr >= bfd_section_vma (abfd, sect)) ++ { ++ struct build_id_addr_sect *candidate; ++ ++ candidate = xmalloc (sizeof *candidate); ++ candidate->next = build_id_addr_sect; ++ build_id_addr_sect = candidate; ++ candidate->sect = sect; ++ } ++} ++ ++struct build_id * ++build_id_addr_get (CORE_ADDR addr) ++{ ++ struct build_id_addr_sect *candidate; ++ struct build_id *retval = NULL; ++ Elf_Internal_Phdr *i_phdr = NULL; ++ bfd_vma loadbase = 0; ++ unsigned e_phnum = 0; ++ ++ if (core_bfd == NULL) ++ return NULL; ++ ++ build_id_addr = addr; ++ gdb_assert (build_id_addr_sect == NULL); ++ bfd_map_over_sections (core_bfd, build_id_addr_candidate, NULL); ++ ++ /* Sections are sorted in the high-to-low VMAs order. ++ Stop the search on the first ELF header we find. ++ Do not continue the search even if it does not contain NT_GNU_BUILD_ID. */ ++ ++ for (candidate = build_id_addr_sect; candidate != NULL; ++ candidate = candidate->next) ++ { ++ i_phdr = elf_get_phdr (core_bfd, ++ bfd_section_vma (core_bfd, candidate->sect), ++ &e_phnum, &loadbase); ++ if (i_phdr != NULL) ++ break; ++ } ++ ++ if (i_phdr != NULL) ++ { ++ retval = build_id_phdr_get (core_bfd, loadbase, e_phnum, i_phdr); ++ xfree (i_phdr); ++ } ++ ++ while (build_id_addr_sect != NULL) ++ { ++ candidate = build_id_addr_sect; ++ build_id_addr_sect = candidate->next; ++ xfree (candidate); ++ } ++ ++ return retval; ++} ++ + /* Return if FILENAME has NT_GNU_BUILD_ID matching the CHECK value. */ + + static int +@@ -1227,7 +1619,7 @@ build_id_verify (const char *filename, s + if (abfd == NULL) + return 0; + +- found = build_id_bfd_get (abfd); ++ found = build_id_bfd_shdr_get (abfd); + + if (found == NULL) + warning (_("File \"%s\" has no build-id, file skipped"), filename); +@@ -1246,8 +1638,9 @@ build_id_verify (const char *filename, s + return retval; + } + +-static char * +-build_id_to_debug_filename (struct build_id *build_id) ++char * ++build_id_to_filename (struct build_id *build_id, char **link_return, ++ int add_debug_suffix) + { + char *link, *s, *retval = NULL; + gdb_byte *data = build_id->data; +@@ -1255,7 +1648,9 @@ build_id_to_debug_filename (struct build + + /* DEBUG_FILE_DIRECTORY/.build-id/ab/cdef */ + link = xmalloc (strlen (debug_file_directory) + (sizeof "/.build-id/" - 1) + 1 +- + 2 * size + (sizeof ".debug" - 1) + 1); ++ + 2 * size ++ + (add_debug_suffix ? sizeof ".debug" - 1 : 0) ++ + 1); + s = link + sprintf (link, "%s/.build-id/", debug_file_directory); + if (size > 0) + { +@@ -1266,12 +1661,14 @@ build_id_to_debug_filename (struct build + *s++ = '/'; + while (size-- > 0) + s += sprintf (s, "%02x", (unsigned) *data++); +- strcpy (s, ".debug"); ++ if (add_debug_suffix) ++ strcpy (s, ".debug"); ++ else ++ *s = 0; + + /* lrealpath() is expensive even for the usually non-existent files. */ + if (access (link, F_OK) == 0) + retval = lrealpath (link); +- xfree (link); + + if (retval != NULL && !build_id_verify (retval, build_id)) + { +@@ -1279,9 +1676,142 @@ build_id_to_debug_filename (struct build + retval = NULL; + } + ++ if (link_return != NULL) ++ *link_return = link; ++ else ++ xfree (link); ++ ++ return retval; ++} ++ ++/* This MISSING_FILEPAIR_HASH tracker is used only for the duplicite messages ++ Try to install the hash file ... ++ avoidance. */ ++ ++struct missing_filepair ++ { ++ char *binary; ++ char *debug; ++ char data[1]; ++ }; ++ ++static struct htab *missing_filepair_hash; ++static struct obstack missing_filepair_obstack; ++ ++static void * ++missing_filepair_xcalloc (size_t nmemb, size_t nmemb_size) ++{ ++ void *retval; ++ size_t size = nmemb * nmemb_size; ++ ++ retval = obstack_alloc (&missing_filepair_obstack, size); ++ memset (retval, 0, size); + return retval; + } + ++static hashval_t ++missing_filepair_hash_func (const struct missing_filepair *elem) ++{ ++ hashval_t retval = 0; ++ ++ retval ^= htab_hash_string (elem->binary); ++ if (elem->debug != NULL) ++ retval ^= htab_hash_string (elem->debug); ++ ++ return retval; ++} ++ ++static int ++missing_filepair_eq (const struct missing_filepair *elem1, ++ const struct missing_filepair *elem2) ++{ ++ return strcmp (elem1->binary, elem2->binary) == 0 ++ && ((elem1->debug == NULL && elem2->debug == NULL) ++ || strcmp (elem1->debug, elem2->debug) == 0); ++} ++ ++static void ++missing_filepair_change (void) ++{ ++ if (missing_filepair_hash != NULL) ++ { ++ obstack_free (&missing_filepair_obstack, NULL); ++ /* All their memory came just from missing_filepair_OBSTACK. */ ++ missing_filepair_hash = NULL; ++ } ++} ++ ++static void ++debug_print_executable_changed (void) ++{ ++ missing_filepair_change (); ++} ++ ++/* Notify user the file BINARY with (possibly NULL) associated separate debug ++ information file DEBUG is missing. DEBUG may or may not be the build-id ++ file such as would be: ++ /usr/lib/debug/.build-id/dd/b1d2ce632721c47bb9e8679f369e2295ce71be.debug ++ */ ++ ++void ++debug_print_missing (const char *binary, const char *debug) ++{ ++ size_t binary_len0 = strlen (binary) + 1; ++ size_t debug_len0 = debug ? strlen (debug) + 1 : 0; ++ struct missing_filepair *missing_filepair; ++ struct missing_filepair **slot; ++ ++ if (build_id_verbose < BUILD_ID_VERBOSE_FILENAMES) ++ return; ++ ++ if (missing_filepair_hash == NULL) ++ { ++ obstack_init (&missing_filepair_obstack); ++ missing_filepair_hash = htab_create_alloc (64, ++ (hashval_t (*) (const void *)) missing_filepair_hash_func, ++ (int (*) (const void *, const void *)) missing_filepair_eq, NULL, ++ missing_filepair_xcalloc, NULL); ++ } ++ ++ missing_filepair = obstack_alloc (&missing_filepair_obstack, ++ sizeof (*missing_filepair) - 1 ++ + binary_len0 + debug_len0); ++ missing_filepair->binary = missing_filepair->data; ++ memcpy (missing_filepair->binary, binary, binary_len0); ++ if (debug != NULL) ++ { ++ missing_filepair->debug = missing_filepair->binary + binary_len0; ++ memcpy (missing_filepair->debug, debug, debug_len0); ++ } ++ else ++ missing_filepair->debug = NULL; ++ ++ slot = (struct missing_filepair **) htab_find_slot (missing_filepair_hash, ++ missing_filepair, ++ INSERT); ++ ++ /* While it may be still printed duplicitely with the missing debuginfo file ++ * it is due to once printing about the binary file build-id link and once ++ * about the .debug file build-id link as both the build-id symlinks are ++ * located in the debuginfo package. */ ++ ++ if (*slot != NULL) ++ { ++ obstack_free (&missing_filepair_obstack, missing_filepair); ++ return; ++ } ++ *slot = missing_filepair; ++ ++ /* We do not collect and flush these messages as each such message ++ already requires its own separate lines. */ ++ ++ fprintf_unfiltered (gdb_stdlog, ++ _("Missing separate debuginfo for %s\n"), binary); ++ if (debug != NULL) ++ fprintf_unfiltered (gdb_stdlog, _("Try to install the hash file %s\n"), ++ debug); ++} ++ + static char * + get_debug_link_info (struct objfile *objfile, unsigned long *crc32_out) + { +@@ -1364,32 +1894,36 @@ static char * + find_separate_debug_file (struct objfile *objfile) + { + asection *sect; +- char *basename; +- char *dir; +- char *debugfile; ++ char *basename = NULL; ++ char *dir = NULL; ++ char *debugfile = NULL; + char *name_copy; +- char *canon_name; ++ char *canon_name = NULL; + bfd_size_type debuglink_size; + unsigned long crc32; + int i; + struct build_id *build_id; ++ char *build_id_filename = NULL; + +- build_id = build_id_bfd_get (objfile->obfd); ++ build_id = build_id_bfd_shdr_get (objfile->obfd); + if (build_id != NULL) + { + char *build_id_name; + +- build_id_name = build_id_to_debug_filename (build_id); ++ build_id_name = build_id_to_filename (build_id, &build_id_filename, 1); + xfree (build_id); + /* Prevent looping on a stripped .debug file. */ + if (build_id_name != NULL && strcmp (build_id_name, objfile->name) == 0) + { +- warning (_("\"%s\": separate debug info file has no debug info"), ++ warning (_("\"%s\": The separate debug info file has no debug info"), + build_id_name); + xfree (build_id_name); + } + else if (build_id_name != NULL) +- return build_id_name; ++ { ++ xfree (build_id_filename); ++ return build_id_name; ++ } + } + + basename = get_debug_link_info (objfile, &crc32); +@@ -1397,7 +1931,7 @@ find_separate_debug_file (struct objfile + if (basename == NULL) + /* There's no separate debug info, hence there's no way we could + load it => no warning. */ +- return NULL; ++ goto cleanup_return_debugfile; + + dir = xstrdup (objfile->name); + +@@ -1413,23 +1947,19 @@ find_separate_debug_file (struct objfile + gdb_assert (i >= 0 && IS_DIR_SEPARATOR (dir[i])); + dir[i+1] = '\0'; + +- debugfile = alloca (strlen (debug_file_directory) + 1 +- + strlen (dir) +- + strlen (DEBUG_SUBDIRECTORY) +- + strlen ("/") +- + strlen (basename) +- + 1); ++ debugfile = xmalloc (strlen (debug_file_directory) + 1 ++ + strlen (dir) ++ + strlen (DEBUG_SUBDIRECTORY) ++ + strlen ("/") ++ + strlen (basename) ++ + 1); + + /* First try in the same directory as the original file. */ + strcpy (debugfile, dir); + strcat (debugfile, basename); + + if (separate_debug_file_exists (debugfile, crc32, objfile->name)) +- { +- xfree (basename); +- xfree (dir); +- return xstrdup (debugfile); +- } ++ goto cleanup_return_debugfile; + + /* Then try in the subdirectory named DEBUG_SUBDIRECTORY. */ + strcpy (debugfile, dir); +@@ -1438,11 +1968,7 @@ find_separate_debug_file (struct objfile + strcat (debugfile, basename); + + if (separate_debug_file_exists (debugfile, crc32, objfile->name)) +- { +- xfree (basename); +- xfree (dir); +- return xstrdup (debugfile); +- } ++ goto cleanup_return_debugfile; + + /* Then try in the global debugfile directory. */ + strcpy (debugfile, debug_file_directory); +@@ -1451,11 +1977,7 @@ find_separate_debug_file (struct objfile + strcat (debugfile, basename); + + if (separate_debug_file_exists (debugfile, crc32, objfile->name)) +- { +- xfree (basename); +- xfree (dir); +- return xstrdup (debugfile); +- } ++ goto cleanup_return_debugfile; + + /* If the file is in the sysroot, try using its base path in the + global debugfile directory. */ +@@ -1470,20 +1992,18 @@ find_separate_debug_file (struct objfile + strcat (debugfile, basename); + + if (separate_debug_file_exists (debugfile, crc32, objfile->name)) +- { +- xfree (canon_name); +- xfree (basename); +- xfree (dir); +- return xstrdup (debugfile); +- } ++ goto cleanup_return_debugfile; + } +- +- if (canon_name) +- xfree (canon_name); + ++ debugfile = NULL; ++ debug_print_missing (objfile->name, build_id_filename); ++ ++cleanup_return_debugfile: ++ xfree (build_id_filename); ++ xfree (canon_name); + xfree (basename); + xfree (dir); +- return NULL; ++ return debugfile; + } + + +@@ -4216,4 +4736,16 @@ Show printing of symbol loading messages + NULL, + NULL, + &setprintlist, &showprintlist); ++ ++ add_setshow_zinteger_cmd ("build-id-verbose", no_class, &build_id_verbose, ++ _("\ ++Set debugging level of the build-id locator."), _("\ ++Show debugging level of the build-id locator."), _("\ ++Level 1 (default) enables printing the missing debug filenames,\n\ ++level 2 also prints the parsing of binaries to find the identificators."), ++ NULL, ++ show_build_id_verbose, ++ &setlist, &showlist); ++ ++ observer_attach_executable_changed (debug_print_executable_changed); + } +Index: gdb-6.8.50.20090302/gdb/symfile.h +=================================================================== +--- gdb-6.8.50.20090302.orig/gdb/symfile.h 2009-03-07 17:04:52.000000000 +0100 ++++ gdb-6.8.50.20090302/gdb/symfile.h 2009-03-07 17:13:33.000000000 +0100 +@@ -372,6 +372,13 @@ extern int symfile_map_offsets_to_segmen + struct symfile_segment_data *get_symfile_segment_data (bfd *abfd); + void free_symfile_segment_data (struct symfile_segment_data *data); + ++/* build-id support. */ ++struct build_id; ++extern struct build_id *build_id_addr_get (CORE_ADDR addr); ++extern char *build_id_to_filename (struct build_id *build_id, ++ char **link_return, int add_debug_suffix); ++extern void debug_print_missing (const char *binary, const char *debug); ++ + /* From dwarf2read.c */ + + extern int dwarf2_has_info (struct objfile *); +Index: gdb-6.8.50.20090302/gdb/testsuite/lib/gdb.exp +=================================================================== +--- gdb-6.8.50.20090302.orig/gdb/testsuite/lib/gdb.exp 2009-03-07 17:04:52.000000000 +0100 ++++ gdb-6.8.50.20090302/gdb/testsuite/lib/gdb.exp 2009-03-07 17:13:33.000000000 +0100 +@@ -1230,6 +1230,16 @@ proc default_gdb_start { } { + warning "Couldn't set the width to 0." + } + } ++ # Turn off the missing warnings as the testsuite does not expect it. ++ send_gdb "set build-id-verbose 0\n" ++ gdb_expect 10 { ++ -re "$gdb_prompt $" { ++ verbose "Disabled the missing debug infos warnings." 2 ++ } ++ timeout { ++ warning "Could not disable the missing debug infos warnings.." ++ } ++ } + return 0; + } + diff --git a/gdb-6.6-bz225783-gdb-debuginfo-paths.patch b/gdb-6.6-bz225783-gdb-debuginfo-paths.patch new file mode 100644 index 0000000..639bbcd --- /dev/null +++ b/gdb-6.6-bz225783-gdb-debuginfo-paths.patch @@ -0,0 +1,33 @@ +https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=225783 + + +Index: gdb-6.8.50.20081128/gdb/Makefile.in +=================================================================== +--- gdb-6.8.50.20081128.orig/gdb/Makefile.in 2008-12-02 23:06:16.000000000 +0100 ++++ gdb-6.8.50.20081128/gdb/Makefile.in 2008-12-02 23:28:02.000000000 +0100 +@@ -1490,8 +1490,10 @@ po/$(PACKAGE).pot: force + + .SUFFIXES: .y .l + .y.c: +- $(SHELL) $(YLWRAP) $< y.tab.c $@.tmp -- $(YACC) $(YFLAGS) +- -sed -e '/extern.*malloc/d' \ ++ rm -f $@ $@.tmp ++ $(SHELL) $(YLWRAP) $< y.tab.c $@ -- $(YACC) $(YFLAGS) && mv $@ $@.tmp \ ++ || (rm -f $@; false) ++ sed -e '/extern.*malloc/d' \ + -e '/extern.*realloc/d' \ + -e '/extern.*free/d' \ + -e '/include.*malloc.h/d' \ +@@ -1500,9 +1502,9 @@ po/$(PACKAGE).pot: force + -e 's/\([ \t;,(]\)free\([ \t]*[&(),]\)/\1xfree\2/g' \ + -e 's/\([ \t;,(]\)free$$/\1xfree/g' \ + -e '/^#line.*y.tab.c/d' \ +- < $@.tmp > $@.new +- -rm $@.tmp +- mv $@.new ./$*.c ++ -e "s/^\(#line.*\)`basename $<`/\1`echo $<|sed 's/\//\\\\\//g'`/" \ ++ < $@.tmp > $@ ++ rm -f $@.tmp + .l.c: + if [ "$(FLEX)" ] && $(FLEX) --version >/dev/null 2>&1; then \ + $(FLEX) -o$@ $< && \ diff --git a/gdb-6.6-bz225783-prelink-path.patch b/gdb-6.6-bz225783-prelink-path.patch new file mode 100644 index 0000000..22c8829 --- /dev/null +++ b/gdb-6.6-bz225783-prelink-path.patch @@ -0,0 +1,27 @@ +https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=225783 + +--- gdb-6.8/gdb/testsuite/gdb.base/prelink.exp.orig 2008-07-12 08:56:43.000000000 +0200 ++++ gdb-6.8/gdb/testsuite/gdb.base/prelink.exp 2008-07-12 08:59:59.000000000 +0200 +@@ -55,7 +55,7 @@ if { [gdb_compile "${srcdir}/${subdir}/$ + # single new unprelinked library address without wasting the first one/two + # memory areas. We do not care of the efficiency of loading such resulting + # exec-shield unfriendly prelinked library. +-if {[catch "system \"prelink -qNR --no-exec-shield ${libfile}\""] != 0} { ++if {[catch "system \"/usr/sbin/prelink -qNR --no-exec-shield ${libfile}\""] != 0} { + # Maybe we don't have prelink. + return -1 + } +@@ -96,11 +96,11 @@ if { $found == 0 } { + return 0 + } + +-if {[catch "system \"prelink -uN ${libfile}\""] != 0} { ++if {[catch "system \"/usr/sbin/prelink -uN ${libfile}\""] != 0} { + untested "${testfile}.so was not prelinked, maybe system libraries are not prelinked?" + return 0 + } +-catch "system \"prelink -qNR --no-exec-shield ${libfile}\"" ++catch "system \"/usr/sbin/prelink -qNR --no-exec-shield ${libfile}\"" + + # Start with a fresh gdb + diff --git a/gdb-6.6-bz229517-gcore-without-terminal.patch b/gdb-6.6-bz229517-gcore-without-terminal.patch new file mode 100644 index 0000000..de34ed5 --- /dev/null +++ b/gdb-6.6-bz229517-gcore-without-terminal.patch @@ -0,0 +1,191 @@ +2007-04-22 Jan Kratochvil + + * gdb_gcore.sh: Redirect GDB from ` + + * gdb.base/gcorebg.exp, gdb.base/gcorebg.c: New files. + + +--- gdb-6.6-orig/gdb/gdb_gcore.sh 2005-12-17 17:33:59.000000000 -0500 ++++ gdb-6.6/gdb/gdb_gcore.sh 2007-04-22 05:42:50.000000000 -0400 +@@ -71,7 +71,9 @@ + quit + EOF + +- gdb -x $tmpfile -batch ++ # ` ++#include ++#include ++#include ++#include ++ ++int main (int argc, char **argv) ++{ ++ pid_t pid = 0; ++ pid_t ppid; ++ char buf[256]; ++ ++ if (argc != 4) ++ { ++ fprintf (stderr, "Syntax: %s {standard|detached} \n", ++ argv[0]); ++ exit (1); ++ } ++ ++ pid = fork (); ++ ++ switch (pid) ++ { ++ case 0: ++ if (strcmp (argv[1], "detached") == 0) ++ setpgrp (); ++ ppid = getppid (); ++ sprintf (buf, "sh %s -o %s %d", argv[2], argv[3], (int) ppid); ++ system (buf); ++ kill (ppid, SIGTERM); ++ break; ++ ++ case -1: ++ perror ("fork err\n"); ++ exit (1); ++ break; ++ ++ default: ++ sleep (60); ++ } ++ ++ return 0; ++} +--- /dev/null 1 Jan 1970 00:00:00 -0000 ++++ ./gdb/testsuite/gdb.base/gcorebg.exp 25 Feb 2007 12:21:20 -0000 +@@ -0,0 +1,120 @@ ++# Copyright 2007 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++# Please email any bugs, comments, and/or additions to this file to: ++# bug-gdb@prep.ai.mit.edu ++ ++# This file was written by Jan Kratochvil . ++# This is a test for `gdb_gcore.sh' functionality. ++# It also tests a regression with `gdb_gcore.sh' being run without its ++# accessible terminal. ++ ++if $tracelevel then { ++ strace $tracelevel ++} ++ ++set prms_id 0 ++set bug_id 0 ++ ++if ![info exists GCORE] { ++ set GCORE "${srcdir}/../gdb_gcore.sh" ++} ++verbose "using GCORE = $GCORE" 2 ++ ++set testfile "gcorebg" ++set srcfile ${testfile}.c ++set binfile ${objdir}/${subdir}/${testfile} ++set corefile ${objdir}/${subdir}/${testfile}.test ++ ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { ++ untested gcorebg.exp ++ return -1 ++} ++ ++# Cleanup. ++ ++proc core_clean {} { ++ global corefile ++ ++ foreach file [glob -nocomplain [join [list $corefile *] ""]] { ++ verbose "Delete file $file" 1 ++ remote_file target delete $file ++ } ++} ++core_clean ++remote_file target delete "./gdb" ++ ++# Generate the core file. ++ ++# Provide `./gdb' for `gdb_gcore.sh' running it as a bare `gdb' command. ++# Setup also `$PATH' appropriately. ++# If GDB was not found let `gdb_gcore.sh' to find the system GDB by `$PATH'. ++if {$GDB != "gdb"} { ++ file link ./gdb $GDB ++} ++global env ++set oldpath $env(PATH) ++set env(PATH) [join [list . $env(PATH)] ":"] ++verbose "PATH = $env(PATH)" 2 ++ ++# Test file body. ++# $detached == "standard" || $detached == "detached" ++ ++proc test_body { detached } { ++ global binfile ++ global GCORE ++ global corefile ++ ++ set res [remote_spawn target "$binfile $detached $GCORE $corefile"] ++ if { $res < 0 || $res == "" } { ++ fail "Spawning $detached gcore" ++ return 1 ++ } ++ pass "Spawning $detached gcore" ++ remote_expect target 20 { ++ timeout { ++ fail "Spawned $detached gcore finished" ++ remote_exec target "kill -9 -[exp_pid -i $res]" ++ return 1 ++ } ++ eof { ++ pass "Spawned $detached gcore finished" ++ remote_wait target 20 ++ } ++ } ++ ++ if {1 == [llength [glob -nocomplain [join [list $corefile *] ""]]]} { ++ pass "Core file generated by $detached gcore" ++ } else { ++ fail "Core file generated by $detached gcore" ++ } ++ core_clean ++} ++ ++# First a general `gdb_gcore.sh' spawn with its controlling terminal available. ++ ++test_body standard ++ ++# And now `gdb_gcore.sh' spawn without its controlling terminal available. ++# It is spawned through `gcorebg.c' using setpgrp (). ++ ++test_body detached ++ ++ ++# Cleanup. ++ ++set env(PATH) $oldpath ++remote_file target delete "./gdb" diff --git a/gdb-6.6-bz230000-power6-disassembly-test.patch b/gdb-6.6-bz230000-power6-disassembly-test.patch new file mode 100644 index 0000000..1ebf31b --- /dev/null +++ b/gdb-6.6-bz230000-power6-disassembly-test.patch @@ -0,0 +1,83 @@ +https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=230000 + +The original testcase + https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=230000#c1 +requires too recent GCC. + + +--- /dev/null 1 Jan 1970 00:00:00 -0000 ++++ ./gdb/testsuite/gdb.arch/powerpc-power6.exp 25 Feb 2007 18:27:39 -0000 +@@ -0,0 +1,54 @@ ++# Copyright 2007 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++# Test PowerPC Power6 instructions disassembly. ++ ++if {![istarget "powerpc*-*-*"]} then { ++ verbose "Skipping PowerPC Power6 instructions disassembly." ++ return ++} ++ ++set testfile "powerpc-power6" ++set srcfile ${testfile}.s ++set objfile ${objdir}/${subdir}/${testfile}.o ++ ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${objfile}" object {debug}] != "" } { ++ untested "PowerPC prologue tests" ++ return -1 ++} ++ ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${objfile} ++ ++# Disassemble the function. ++ ++gdb_test "disass func" ":\tblr\r\n.*" "Basic disassembly" ++ ++gdb_test "disass func" ":\tdcbzl *r8,r9\r\n.*" "Power5 disassembly dcbzl" ++gdb_test "disass func" ":\tfrsqrtes *f10,f11\r\n.*" "Power5 disassembly frsqrtes" ++gdb_test "disass func" ":\tdadd *f1,f2,f1\r\n.*" "Power6 disassembly dadd" ++gdb_test "disass func" ":\tdaddq *f1,f2,f1\r\n.*" "Power6 disassembly daddq" ++gdb_test "disass func" ":\tdsub *f1,f2,f1\r\n.*" "Power6 disassembly dsub" ++gdb_test "disass func" ":\tdsubq *f1,f2,f1\r\n.*" "Power6 disassembly dsubq" ++gdb_test "disass func" ":\tdmul *f1,f2,f1\r\n.*" "Power6 disassembly dmul" ++gdb_test "disass func" ":\tdmulq *f1,f2,f1\r\n.*" "Power6 disassembly dmulq" ++gdb_test "disass func" ":\tddiv *f1,f2,f1\r\n.*" "Power6 disassembly ddiv" ++gdb_test "disass func" ":\tddivq *f1,f2,f1\r\n.*" "Power6 disassembly ddivq" ++gdb_test "disass func" ":\tdcmpu *cr1,f2,f1\r\n.*" "Power6 disassembly dcmpu" ++gdb_test "disass func" ":\tdcmpuq *cr1,f2,f1\r\n.*" "Power6 disassembly dcmpuq" +--- /dev/null 1 Jan 1970 00:00:00 -0000 ++++ ./gdb/testsuite/gdb.arch/powerpc-power6.s 25 Feb 2007 18:27:39 -0000 +@@ -0,0 +1,16 @@ ++ .text ++ .globl func ++func: ++ blr ++ .long 0x7c284fec /* dcbzl r8,r9 */ ++ .long 0xed405834 /* frsqrtes f10,f11 */ ++ .long 0xec220804 /* dadd f1,f2,f1 */ ++ .long 0xfc220804 /* daddq f1,f2,f1 */ ++ .long 0xec220c04 /* dsub f1,f2,f1 */ ++ .long 0xfc220c04 /* dsubq f1,f2,f1 */ ++ .long 0xec220844 /* dmul f1,f2,f1 */ ++ .long 0xfc220844 /* dmulq f1,f2,f1 */ ++ .long 0xec220c44 /* ddiv f1,f2,f1 */ ++ .long 0xfc220c44 /* ddivq f1,f2,f1 */ ++ .long 0xec820d04 /* dcmpu cr1,f2,f1 */ ++ .long 0xfc820d04 /* dcmpuq cr1,f2,f1 */ diff --git a/gdb-6.6-bz235197-fork-detach-info.patch b/gdb-6.6-bz235197-fork-detach-info.patch new file mode 100644 index 0000000..9d17778 --- /dev/null +++ b/gdb-6.6-bz235197-fork-detach-info.patch @@ -0,0 +1,128 @@ +2008-03-01 Jan Kratochvil + + Port to GDB-6.8pre. + Remove the `[' character from the GDB-6.8 default message. + +Index: gdb-6.7.50.20080227/gdb/linux-nat.c +=================================================================== +--- gdb-6.7.50.20080227.orig/gdb/linux-nat.c 2008-03-01 10:30:48.000000000 +0100 ++++ gdb-6.7.50.20080227/gdb/linux-nat.c 2008-03-01 10:48:25.000000000 +0100 +@@ -415,7 +415,7 @@ linux_child_follow_fork (struct target_o + /* Detach new forked process? */ + if (detach_fork) + { +- if (info_verbose || debug_linux_nat) ++ if (1 /* Fedora Bug 235197 */ || info_verbose || debug_linux_nat) + { + target_terminal_ours (); + fprintf_filtered (gdb_stdlog, +Index: gdb-6.7.50.20080227/gdb/testsuite/gdb.base/fork-detach.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.7.50.20080227/gdb/testsuite/gdb.base/fork-detach.c 2008-03-01 10:30:49.000000000 +0100 +@@ -0,0 +1,57 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2007 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++ Please email any bugs, comments, and/or additions to this file to: ++ bug-gdb@prep.ai.mit.edu */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++static void func (void) ++{ ++} ++ ++int main (void) ++{ ++ pid_t child; ++ ++ child = fork (); ++ switch (child) ++ { ++ case -1: ++ abort (); ++ case 0: ++ func (); ++ break; ++ default: ++ { ++/* We do not test the switching to the other fork by GDB `fork 1'. */ ++#if 0 ++ pid_t got; ++ ++ got = waitpid (child, NULL, 0); ++ assert (got == child); ++#endif ++ break; ++ } ++ } ++ return 0; ++} +Index: gdb-6.7.50.20080227/gdb/testsuite/gdb.base/fork-detach.exp +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.7.50.20080227/gdb/testsuite/gdb.base/fork-detach.exp 2008-03-01 10:49:36.000000000 +0100 +@@ -0,0 +1,43 @@ ++# Copyright 2007 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++if $tracelevel then { ++ strace $tracelevel ++} ++ ++set prms_id 0 ++set bug_id 0 ++ ++set testfile fork-detach ++set srcfile ${testfile}.c ++set binfile ${objdir}/${subdir}/${testfile} ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { ++ untested "Couldn't compile test program" ++ return -1 ++} ++ ++# Get things started. ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++gdb_run_cmd ++# `Starting program: .*' prefix is available since gdb-6.7. ++gdb_test "" \ ++ "Detaching after fork from child process.*Program exited normally\\..*" \ ++ "Info message caught" diff --git a/gdb-6.6-bz237572-ppc-atomic-sequence-test.patch b/gdb-6.6-bz237572-ppc-atomic-sequence-test.patch new file mode 100644 index 0000000..928c7fb --- /dev/null +++ b/gdb-6.6-bz237572-ppc-atomic-sequence-test.patch @@ -0,0 +1,270 @@ +2007-06-25 Jan Kratochvil + + * gdb.threads/atomic-seq-threaded.c, + gdb.threads/atomic-seq-threaded.exp: New files. + +Index: gdb-6.8.50.20081128/gdb/testsuite/gdb.threads/atomic-seq-threaded.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8.50.20081128/gdb/testsuite/gdb.threads/atomic-seq-threaded.c 2008-12-08 22:27:01.000000000 +0100 +@@ -0,0 +1,171 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2007 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ++ MA 02110-1301, USA. */ ++ ++/* Test stepping over RISC atomic sequences. ++ This variant testcases the code for stepping another thread while skipping ++ over the atomic sequence in the former thread ++ (STEPPING_PAST_SINGLESTEP_BREAKPOINT). ++ Code comes from gcc/testsuite/gcc.dg/sync-2.c */ ++ ++/* { dg-options "-march=i486" { target { { i?86-*-* x86_64-*-* } && ilp32 } } } */ ++/* { dg-options "-mcpu=v9" { target sparc*-*-* } } */ ++ ++/* Test functionality of the intrinsics for 'short' and 'char'. */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#define LOOPS 2 ++ ++static int unused; ++ ++static char AI[18]; ++static char init_qi[18] = { 3,5,7,9,0,0,0,0,-1,0,0,0,0,0,-1,0,0,0 }; ++static char test_qi[18] = { 3,5,7,9,1,4,22,-12,7,8,9,7,1,-12,7,8,9,7 }; ++ ++static void ++do_qi (void) ++{ ++ if (__sync_fetch_and_add(AI+4, 1) != 0) ++ abort (); ++ if (__sync_fetch_and_add(AI+5, 4) != 0) ++ abort (); ++ if (__sync_fetch_and_add(AI+6, 22) != 0) ++ abort (); ++ if (__sync_fetch_and_sub(AI+7, 12) != 0) ++ abort (); ++ if (__sync_fetch_and_and(AI+8, 7) != (char)-1) ++ abort (); ++ if (__sync_fetch_and_or(AI+9, 8) != 0) ++ abort (); ++ if (__sync_fetch_and_xor(AI+10, 9) != 0) ++ abort (); ++ if (__sync_fetch_and_nand(AI+11, 7) != 0) ++ abort (); ++ ++ if (__sync_add_and_fetch(AI+12, 1) != 1) ++ abort (); ++ if (__sync_sub_and_fetch(AI+13, 12) != (char)-12) ++ abort (); ++ if (__sync_and_and_fetch(AI+14, 7) != 7) ++ abort (); ++ if (__sync_or_and_fetch(AI+15, 8) != 8) ++ abort (); ++ if (__sync_xor_and_fetch(AI+16, 9) != 9) ++ abort (); ++ if (__sync_nand_and_fetch(AI+17, 7) != 7) ++ abort (); ++} ++ ++static short AL[18]; ++static short init_hi[18] = { 3,5,7,9,0,0,0,0,-1,0,0,0,0,0,-1,0,0,0 }; ++static short test_hi[18] = { 3,5,7,9,1,4,22,-12,7,8,9,7,1,-12,7,8,9,7 }; ++ ++static void ++do_hi (void) ++{ ++ if (__sync_fetch_and_add(AL+4, 1) != 0) ++ abort (); ++ if (__sync_fetch_and_add(AL+5, 4) != 0) ++ abort (); ++ if (__sync_fetch_and_add(AL+6, 22) != 0) ++ abort (); ++ if (__sync_fetch_and_sub(AL+7, 12) != 0) ++ abort (); ++ if (__sync_fetch_and_and(AL+8, 7) != -1) ++ abort (); ++ if (__sync_fetch_and_or(AL+9, 8) != 0) ++ abort (); ++ if (__sync_fetch_and_xor(AL+10, 9) != 0) ++ abort (); ++ if (__sync_fetch_and_nand(AL+11, 7) != 0) ++ abort (); ++ ++ if (__sync_add_and_fetch(AL+12, 1) != 1) ++ abort (); ++ if (__sync_sub_and_fetch(AL+13, 12) != -12) ++ abort (); ++ if (__sync_and_and_fetch(AL+14, 7) != 7) ++ abort (); ++ if (__sync_or_and_fetch(AL+15, 8) != 8) ++ abort (); ++ if (__sync_xor_and_fetch(AL+16, 9) != 9) ++ abort (); ++ if (__sync_nand_and_fetch(AL+17, 7) != 7) ++ abort (); ++} ++ ++static void * ++start1 (void *arg) ++{ ++ unsigned loop; ++ sleep(1); ++ ++ for (loop = 0; loop < LOOPS; loop++) ++ { ++ memcpy(AI, init_qi, sizeof(init_qi)); ++ ++ do_qi (); ++ ++ if (memcmp (AI, test_qi, sizeof(test_qi))) ++ abort (); ++ } ++ ++ return arg; /* _delete1_ */ ++} ++ ++static void * ++start2 (void *arg) ++{ ++ unsigned loop; ++ ++ for (loop = 0; loop < LOOPS; loop++) ++ { ++ memcpy(AL, init_hi, sizeof(init_hi)); ++ ++ do_hi (); ++ ++ if (memcmp (AL, test_hi, sizeof(test_hi))) ++ abort (); ++ } ++ ++ return arg; /* _delete2_ */ ++} ++ ++int ++main (int argc, char **argv) ++{ ++ pthread_t thread; ++ int i; ++ ++ i = pthread_create (&thread, NULL, start1, NULL); /* _create_ */ ++ assert (i == 0); /* _create_after_ */ ++ ++ sleep (1); ++ ++ start2 (NULL); ++ ++ i = pthread_join (thread, NULL); /* _delete_ */ ++ assert (i == 0); ++ ++ return 0; /* _exit_ */ ++} +Index: gdb-6.8.50.20081128/gdb/testsuite/gdb.threads/atomic-seq-threaded.exp +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8.50.20081128/gdb/testsuite/gdb.threads/atomic-seq-threaded.exp 2008-12-08 22:31:01.000000000 +0100 +@@ -0,0 +1,84 @@ ++# atomic-seq-threaded.exp -- Test case for stepping over RISC atomic code seqs. ++# This variant testcases the code for stepping another thread while skipping ++# over the atomic sequence in the former thread ++# (STEPPING_PAST_SINGLESTEP_BREAKPOINT). ++# Copyright (C) 2007 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ ++ ++# Please email any bugs, comments, and/or additions to this file to: ++# bug-gdb@prep.ai.mit.edu ++ ++set testfile atomic-seq-threaded ++set srcfile ${testfile}.c ++set binfile ${objdir}/${subdir}/${testfile} ++ ++foreach opts {{} {compiler=gcc4} {FAIL}} { ++ if {$opts eq "FAIL"} { ++ return -1 ++ } ++ if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable [list debug $opts]] eq "" } { ++ break ++ } ++} ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++ ++gdb_load ${binfile} ++if ![runto_main] then { ++ fail "Can't run to main" ++ return 0 ++} ++ ++# pthread_create () will not pass even on x86_64 with software watchpoint. ++# Pass after pthread_create () without any watchpoint active. ++set line [gdb_get_line_number "_create_after_"] ++gdb_test "tbreak $line" \ ++ "reakpoint (\[0-9\]+) at .*$srcfile, line $line\..*" \ ++ "set breakpoint after pthread_create ()" ++gdb_test "c" \ ++ ".*/\\* _create_after_ \\*/.*" \ ++ "run till after pthread_create ()" ++ ++# Without a watchpoint being software no single-stepping would be used. ++set test "Start (software) watchpoint" ++gdb_test_multiple "watch unused" $test { ++ -re "Watchpoint \[0-9\]+: unused.*$gdb_prompt $" { ++ pass $test ++ } ++ -re "Hardware watchpoint \[0-9\]+: unused.*$gdb_prompt $" { ++ # We do not test the goal but still the whole testcase should pass. ++ unsupported $test ++ } ++} ++ ++# More thorough testing of the scheduling logic. ++gdb_test "set scheduler-locking step" "" ++ ++# Critical code path is stepped through at this point. ++set line [gdb_get_line_number "_exit_"] ++gdb_test "tbreak $line" \ ++ "reakpoint \[0-9\]+ at .*$srcfile, line $line\..*" \ ++ "set breakpoint at _exit_" ++gdb_test "c" \ ++ ".*/\\* _exit_ \\*/.*" \ ++ "run till _exit_" ++ ++# Just a nonproblematic program exit. ++gdb_test "c" \ ++ ".*Program exited normally\\..*" \ ++ "run till program exit" diff --git a/gdb-6.6-bz247354-leader-exit-fix.patch b/gdb-6.6-bz247354-leader-exit-fix.patch new file mode 100644 index 0000000..37c61dd --- /dev/null +++ b/gdb-6.6-bz247354-leader-exit-fix.patch @@ -0,0 +1,142 @@ +2007-07-08 Jan Kratochvil + + * linux-nat.c (linux_lwp_is_zombie): New function. + (wait_lwp): Fix lockup on exit of the thread group leader. + (linux_xfer_partial): Renamed to ... + (linux_xfer_partial_lwp): ... here. + (linux_xfer_partial): New function wrapping LINUX_XFER_PARTIAL_LWP. + +2008-02-24 Jan Kratochvil + + Port to GDB-6.8pre. + +Index: gdb-6.8.50.20081209/gdb/linux-nat.c +=================================================================== +--- gdb-6.8.50.20081209.orig/gdb/linux-nat.c 2008-12-10 01:27:34.000000000 +0100 ++++ gdb-6.8.50.20081209/gdb/linux-nat.c 2008-12-10 01:28:14.000000000 +0100 +@@ -1981,6 +1981,31 @@ linux_handle_extended_wait (struct lwp_i + _("unknown ptrace event %d"), event); + } + ++static int ++linux_lwp_is_zombie (long lwp) ++{ ++ char buffer[MAXPATHLEN]; ++ FILE *procfile; ++ int retval = 0; ++ ++ sprintf (buffer, "/proc/%ld/status", lwp); ++ procfile = fopen (buffer, "r"); ++ if (procfile == NULL) ++ { ++ warning (_("unable to open /proc file '%s'"), buffer); ++ return 0; ++ } ++ while (fgets (buffer, sizeof (buffer), procfile) != NULL) ++ if (strcmp (buffer, "State:\tZ (zombie)\n") == 0) ++ { ++ retval = 1; ++ break; ++ } ++ fclose (procfile); ++ ++ return retval; ++} ++ + /* Wait for LP to stop. Returns the wait status, or 0 if the LWP has + exited. */ + +@@ -1988,16 +2013,31 @@ static int + wait_lwp (struct lwp_info *lp) + { + pid_t pid; +- int status; ++ int status = 0; + int thread_dead = 0; + + gdb_assert (!lp->stopped); + gdb_assert (lp->status == 0); + +- pid = my_waitpid (GET_LWP (lp->ptid), &status, 0); +- if (pid == -1 && errno == ECHILD) ++ /* Thread group leader may have exited but we would lock up by WAITPID as it ++ waits on all its threads; __WCLONE is not applicable for the leader. ++ The thread leader restrictions is only a performance optimization here. ++ LINUX_NAT_THREAD_ALIVE cannot be used here as it requires a STOPPED ++ process; it gets ESRCH both for the zombie and for running processes. */ ++ if (is_lwp (lp->ptid) && GET_PID (lp->ptid) == GET_LWP (lp->ptid) ++ && linux_lwp_is_zombie (GET_LWP (lp->ptid))) ++ { ++ thread_dead = 1; ++ if (debug_linux_nat) ++ fprintf_unfiltered (gdb_stdlog, "WL: Threads leader %s vanished.\n", ++ target_pid_to_str (lp->ptid)); ++ } ++ ++ if (!thread_dead) + { +- pid = my_waitpid (GET_LWP (lp->ptid), &status, __WCLONE); ++ pid = my_waitpid (GET_LWP (lp->ptid), &status, 0); ++ if (pid == -1 && errno == ECHILD) ++ pid = my_waitpid (GET_LWP (lp->ptid), &status, __WCLONE); + if (pid == -1 && errno == ECHILD) + { + /* The thread has previously exited. We need to delete it +@@ -4153,8 +4193,10 @@ linux_nat_xfer_osdata (struct target_ops + return len; + } + ++/* Transfer from the specific LWP currently set by PID of INFERIOR_PTID. */ ++ + static LONGEST +-linux_xfer_partial (struct target_ops *ops, enum target_object object, ++linux_xfer_partial_lwp (struct target_ops *ops, enum target_object object, + const char *annex, gdb_byte *readbuf, + const gdb_byte *writebuf, ULONGEST offset, LONGEST len) + { +@@ -4201,6 +4243,45 @@ linux_xfer_partial (struct target_ops *o + offset, len); + } + ++/* nptl_db expects being able to transfer memory just by specifying PID. ++ After the thread group leader exists the Linux kernel turns the task ++ into zombie no longer permitting accesses to its memory. ++ Transfer the memory from an arbitrary LWP_LIST entry in such case. */ ++ ++static LONGEST ++linux_xfer_partial (struct target_ops *ops, enum target_object object, ++ const char *annex, gdb_byte *readbuf, ++ const gdb_byte *writebuf, ULONGEST offset, LONGEST len) ++{ ++ LONGEST xfer; ++ struct lwp_info *lp; ++ /* Not using SAVE_INFERIOR_PTID already here for better performance. */ ++ struct cleanup *old_chain = NULL; ++ ptid_t inferior_ptid_orig = inferior_ptid; ++ ++ errno = 0; ++ xfer = linux_xfer_partial_lwp (ops, object, annex, readbuf, writebuf, ++ offset, len); ++ ++ for (lp = lwp_list; xfer == 0 && (errno == EACCES || errno == ESRCH) ++ && lp != NULL; lp = lp->next) ++ { ++ if (!is_lwp (lp->ptid) || ptid_equal (lp->ptid, inferior_ptid_orig)) ++ continue; ++ ++ if (old_chain == NULL) ++ old_chain = save_inferior_ptid (); ++ inferior_ptid = BUILD_LWP (GET_LWP (lp->ptid), GET_LWP (lp->ptid)); ++ errno = 0; ++ xfer = linux_xfer_partial_lwp (ops, object, annex, readbuf, writebuf, ++ offset, len); ++ } ++ ++ if (old_chain != NULL) ++ do_cleanups (old_chain); ++ return xfer; ++} ++ + /* Create a prototype generic GNU/Linux target. The client can override + it with local methods. */ + diff --git a/gdb-6.6-bz247354-leader-exit-test.patch b/gdb-6.6-bz247354-leader-exit-test.patch new file mode 100644 index 0000000..5d26789 --- /dev/null +++ b/gdb-6.6-bz247354-leader-exit-test.patch @@ -0,0 +1,121 @@ +2007-07-07 Jan Kratochvil + + * gdb.threads/leader-exit.c, gdb.threads/leader-exit.exp: New files. + +--- /dev/null 1 Jan 1970 00:00:00 -0000 ++++ ./gdb/testsuite/gdb.threads/leader-exit.c 7 Jul 2007 15:21:57 -0000 +@@ -0,0 +1,47 @@ ++/* Clean exit of the thread group leader should not break GDB. ++ ++ Copyright 2007 Free Software Foundation, Inc. ++ ++ This file is part of GDB. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place - Suite 330, ++ Boston, MA 02111-1307, USA. */ ++ ++#include ++#include ++#include ++ ++static void *start (void *arg) ++{ ++ for (;;) ++ pause (); ++ /* NOTREACHED */ ++ assert (0); ++ return arg; ++} ++ ++int main (void) ++{ ++ pthread_t thread; ++ int i; ++ ++ i = pthread_create (&thread, NULL, start, NULL); /* create1 */ ++ assert (i == 0); ++ ++ pthread_exit (NULL); ++ /* NOTREACHED */ ++ assert (0); ++ return 0; ++} +--- /dev/null 1 Jan 1970 00:00:00 -0000 ++++ ./gdb/testsuite/gdb.threads/leader-exit.exp 7 Jul 2007 15:21:57 -0000 +@@ -0,0 +1,64 @@ ++# Copyright (C) 2007 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++# Exit of the thread group leader should not break GDB. ++ ++# This file was written by Jan Kratochvil . ++ ++if $tracelevel then { ++ strace $tracelevel ++} ++ ++set testfile "leader-exit" ++set srcfile ${testfile}.c ++set binfile ${objdir}/${subdir}/${testfile} ++ ++if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { ++ return -1 ++} ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++gdb_run_cmd ++ ++proc stop_process { description } { ++ global gdb_prompt ++ ++ # For this to work we must be sure to consume the "Continuing." ++ # message first, or GDB's signal handler may not be in place. ++ after 1000 {send_gdb "\003"} ++ gdb_expect { ++ -re "Program received signal SIGINT.*$gdb_prompt $" ++ { ++ pass $description ++ } ++ timeout ++ { ++ fail "$description (timeout)" ++ } ++ } ++} ++ ++# Prevent races. ++sleep 8 ++ ++stop_process "Threads could be stopped" ++ ++gdb_test "info threads" \ ++ "\\* 2 Thread \[^\r\n\]* in \[^\r\n\]*" \ ++ "Single thread has been left" diff --git a/gdb-6.6-gcore32-test.patch b/gdb-6.6-gcore32-test.patch new file mode 100644 index 0000000..4ebfbeb --- /dev/null +++ b/gdb-6.6-gcore32-test.patch @@ -0,0 +1,216 @@ +Test GCORE on 32bit inferiors on 64bit platforms. + +UNSUPPORTED results are valid for `-m64' on 32bit targets. + + +Index: gdb-6.8/gdb/testsuite/gdb.base/gcore.exp +=================================================================== +--- gdb-6.8.orig/gdb/testsuite/gdb.base/gcore.exp 2008-01-01 23:53:19.000000000 +0100 ++++ gdb-6.8/gdb/testsuite/gdb.base/gcore.exp 2008-07-14 10:28:05.000000000 +0200 +@@ -30,9 +30,14 @@ set testfile "gcore" + set srcfile ${testfile}.c + set binfile ${objdir}/${subdir}/${testfile} + +-if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { +- untested gcore.exp +- return -1 ++# `-static-libgcc' to avoid dependency on `libgcc.{i386,ppc}'. ++foreach additional_flags {{} {-m32 -static-libgcc} {-m64 -static-libgcc}} { ++ ++set prefix "arch{$additional_flags}:" ++ ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable [list debug additional_flags=$additional_flags]] != "" } { ++ unsupported "${prefix} gcore.exp" ++ continue + } + + # Start with a fresh gdb. +@@ -47,23 +52,23 @@ send_gdb "help gcore\n" + gdb_expect { + -re "Undefined command: .gcore.*$gdb_prompt $" { + # gcore command not supported -- nothing to test here. +- unsupported "gdb does not support gcore on this target" +- return -1; ++ unsupported "${prefix} gdb does not support gcore on this target" ++ continue + } + -re "Save a core file .*$gdb_prompt $" { +- pass "help gcore" ++ pass "${prefix} help gcore" + } + -re ".*$gdb_prompt $" { +- fail "help gcore" ++ fail "${prefix} help gcore" + } + timeout { +- fail "help gcore (timeout)" ++ fail "${prefix} help gcore (timeout)" + } + } + + if { ! [ runto_main ] } then { +- untested gcore.exp +- return -1 ++ untested "${prefix} gcore.exp" ++ continue + } + + proc capture_command_output { command prefix } { +@@ -77,7 +82,7 @@ proc capture_command_output { command pr + set output_string $expect_out(1,string) + } + default { +- fail "capture_command_output failed on $command." ++ fail "${prefix} capture_command_output failed on $command." + } + } + return $output_string +@@ -109,22 +114,22 @@ set escapedfilename [string_to_regexp ${ + + set core_supported 0 + gdb_test_multiple "gcore ${objdir}/${subdir}/gcore.test" \ +- "save a corefile" \ ++ "${prefix} save a corefile" \ + { + -re "Saved corefile ${escapedfilename}\[\r\n\]+$gdb_prompt $" { +- pass "save a corefile" ++ pass "${prefix} save a corefile" + global core_supported + set core_supported 1 + } + -re "Can't create a corefile\[\r\n\]+$gdb_prompt $" { +- unsupported "save a corefile" ++ unsupported "${prefix} save a corefile" + global core_supported + set core_supported 0 + } + } + + if {!$core_supported} { +- return -1 ++ continue + } + + # Now restart gdb and load the corefile. +@@ -136,31 +141,31 @@ gdb_load ${binfile} + send_gdb "core ${objdir}/${subdir}/gcore.test\n" + gdb_expect { + -re ".* is not a core dump:.*$gdb_prompt $" { +- fail "re-load generated corefile (bad file format)" ++ fail "${prefix} re-load generated corefile (bad file format)" + # No use proceeding from here. +- return; ++ continue + } + -re ".*: No such file or directory.*$gdb_prompt $" { +- fail "re-load generated corefile (file not found)" ++ fail "${prefix} re-load generated corefile (file not found)" + # No use proceeding from here. +- return; ++ continue + } + -re ".*Couldn't find .* registers in core file.*$gdb_prompt $" { +- fail "re-load generated corefile (incomplete note section)" ++ fail "${prefix} re-load generated corefile (incomplete note section)" + } + -re "Core was generated by .*$gdb_prompt $" { +- pass "re-load generated corefile" ++ pass "${prefix} re-load generated corefile" + } + -re ".*$gdb_prompt $" { +- fail "re-load generated corefile" ++ fail "${prefix} re-load generated corefile" + } + timeout { +- fail "re-load generated corefile (timeout)" ++ fail "${prefix} re-load generated corefile (timeout)" + } + } + + send_gdb "where\n" +-gdb_expect_list "where in corefile" ".*$gdb_prompt $" { ++gdb_expect_list "${prefix} where in corefile" ".*$gdb_prompt $" { + ".*\[\r\n\]+#0 .* terminal_func \\(\\) at " + ".*\[\r\n\]+#1 .* array_func \\(\\) at " + ".*\[\r\n\]+#2 .* factorial_func \\(value=1\\) at " +@@ -174,61 +179,64 @@ gdb_expect_list "where in corefile" ".*$ + + set post_corefile_regs [capture_command_output "info registers" ""] + if ![string compare $pre_corefile_regs $post_corefile_regs] then { +- pass "corefile restored general registers" ++ pass "${prefix} corefile restored general registers" + } else { +- fail "corefile restored general registers" ++ fail "${prefix} corefile restored general registers" + } + + set post_corefile_allregs [capture_command_output "info all-reg" ""] + if ![string compare $pre_corefile_allregs $post_corefile_allregs] then { +- pass "corefile restored all registers" ++ pass "${prefix} corefile restored all registers" + } else { +- fail "corefile restored all registers" ++ fail "${prefix} corefile restored all registers" + } + + set post_corefile_extern_array \ + [capture_command_output "print extern_array" "$print_prefix"] + if ![string compare $pre_corefile_extern_array $post_corefile_extern_array] { +- pass "corefile restored extern array" ++ pass "${prefix} corefile restored extern array" + } else { +- fail "corefile restored extern array" ++ fail "${prefix} corefile restored extern array" + } + + set post_corefile_static_array \ + [capture_command_output "print static_array" "$print_prefix"] + if ![string compare $pre_corefile_static_array $post_corefile_static_array] { +- pass "corefile restored static array" ++ pass "${prefix} corefile restored static array" + } else { +- fail "corefile restored static array" ++ fail "${prefix} corefile restored static array" + } + + set post_corefile_uninit_array \ + [capture_command_output "print un_initialized_array" "$print_prefix"] + if ![string compare $pre_corefile_uninit_array $post_corefile_uninit_array] { +- pass "corefile restored un-initialized array" ++ pass "${prefix} corefile restored un-initialized array" + } else { +- fail "corefile restored un-initialized array" ++ fail "${prefix} corefile restored un-initialized array" + } + + set post_corefile_heap_string \ + [capture_command_output "print heap_string" "$print_prefix"] + if ![string compare $pre_corefile_heap_string $post_corefile_heap_string] { +- pass "corefile restored heap array" ++ pass "${prefix} corefile restored heap array" + } else { +- fail "corefile restored heap array" ++ fail "${prefix} corefile restored heap array" + } + + set post_corefile_local_array \ + [capture_command_output "print array_func::local_array" "$print_prefix"] + if ![string compare $pre_corefile_local_array $post_corefile_local_array] { +- pass "corefile restored stack array" ++ pass "${prefix} corefile restored stack array" + } else { +- fail "corefile restored stack array" ++ fail "${prefix} corefile restored stack array" + } + + set post_corefile_backtrace [capture_command_output "backtrace" ""] + if ![string compare $pre_corefile_backtrace $post_corefile_backtrace] { +- pass "corefile restored backtrace" ++ pass "${prefix} corefile restored backtrace" + } else { +- fail "corefile restored backtrace" ++ fail "${prefix} corefile restored backtrace" ++} ++ ++# $additional_flags: + } diff --git a/gdb-6.6-multifork-debugreg.patch b/gdb-6.6-multifork-debugreg.patch new file mode 100644 index 0000000..8e8bca5 --- /dev/null +++ b/gdb-6.6-multifork-debugreg.patch @@ -0,0 +1,1337 @@ +http://sourceware.org/ml/gdb-patches/2008-01/msg00042.html +[ Backported for GDB-6.6 (only removed the new file inclusion). ] + ++ + +2007-09-16 Daniel Jacobowitz + Jeff Johnston + + * gdb.texinfo (Setting Watchpoints): Adjust warning text about + multi-threaded watchpoints. + +2007-12-15 Jan Kratochvil + + * gdb.texinfo (Setting Watchpoints): New paragraph on the software + watchpoints safety wrt `set scheduler-locking'. + +2008-03-01 Jan Kratochvil + + Port to GDB-6.8pre. + +2008-03-31 Jan Kratochvil + + * gdb.threads/watchpoint-fork-forkoff.c (forkoff): New delay after the + parent/child messages to fix a race. + +2008-05-28 Jan Kratochvil + + * s390-nat.c (s390_fix_watch_points): Fix its compilation failure + - rename it to S390_FIX_WATCH_POINTS_LIST. + +Index: gdb-6.8.50.20090209/gdb/amd64-linux-nat.c +=================================================================== +--- gdb-6.8.50.20090209.orig/gdb/amd64-linux-nat.c 2009-02-09 16:02:27.000000000 +0100 ++++ gdb-6.8.50.20090209/gdb/amd64-linux-nat.c 2009-02-09 16:03:30.000000000 +0100 +@@ -408,25 +408,43 @@ amd64_linux_dr_set (ptid_t ptid, int reg + void + amd64_linux_dr_set_control (unsigned long control) + { +- struct lwp_info *lp; +- ptid_t ptid; +- + amd64_linux_dr[DR_CONTROL] = control; +- ALL_LWPS (lp, ptid) +- amd64_linux_dr_set (ptid, DR_CONTROL, control); ++ ++ /* I386_DETACH_BREAKPOINTS may need to reset the registers on single process ++ not listed for ALL_LWPS. */ ++ ++ if (ptid_get_lwp (inferior_ptid) == 0) ++ amd64_linux_dr_set (inferior_ptid, DR_CONTROL, control); ++ else ++ { ++ struct lwp_info *lp; ++ ptid_t ptid; ++ ++ ALL_LWPS (lp, ptid) ++ amd64_linux_dr_set (ptid, DR_CONTROL, control); ++ } + } + + void + amd64_linux_dr_set_addr (int regnum, CORE_ADDR addr) + { +- struct lwp_info *lp; +- ptid_t ptid; +- + gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR); + + amd64_linux_dr[DR_FIRSTADDR + regnum] = addr; +- ALL_LWPS (lp, ptid) +- amd64_linux_dr_set (ptid, DR_FIRSTADDR + regnum, addr); ++ ++ /* I386_DETACH_BREAKPOINTS may need to reset the registers on single process ++ not listed for ALL_LWPS. */ ++ ++ if (ptid_get_lwp (inferior_ptid) == 0) ++ amd64_linux_dr_set (inferior_ptid, DR_FIRSTADDR + regnum, addr); ++ else ++ { ++ struct lwp_info *lp; ++ ptid_t ptid; ++ ++ ALL_LWPS (lp, ptid) ++ amd64_linux_dr_set (ptid, DR_FIRSTADDR + regnum, addr); ++ } + } + + void +@@ -451,6 +469,41 @@ amd64_linux_new_thread (ptid_t ptid) + + amd64_linux_dr_set (ptid, DR_CONTROL, amd64_linux_dr[DR_CONTROL]); + } ++ ++/* TO_FOLLOW_FORK stores here the PID under DETACH_BREAKPOINTS for the child ++ process of traced FORK. We must clear such watchpoints only once during ++ DETACH_BREAKPOINTS. */ ++ ++static int amd64_linux_detach_breakpoints_pid; ++ ++/* Remove a watchpoint that watched the memory region which starts at ++ address ADDR, whose length is LEN bytes, and for accesses of the ++ type TYPE. Return 0 on success, -1 on failure. */ ++int ++amd64_linux_remove_watchpoint (CORE_ADDR addr, int len, int type) ++{ ++ if (ptid_get_pid (inferior_ptid) == amd64_linux_detach_breakpoints_pid) ++ return 0; ++ /* FOLLOW-FORK-MODE CHILD runs later the CHILD with no restrictions. */ ++ amd64_linux_detach_breakpoints_pid = 0; ++ ++ return i386_remove_watchpoint (addr, len, type); ++} ++ ++static void ++amd64_linux_detach_breakpoints (int detached_pid) ++{ ++ struct cleanup *old_chain = save_inferior_ptid (); ++ int i; ++ ++ amd64_linux_detach_breakpoints_pid = detached_pid; ++ /* Depend on `!is_lwp (inferior_ptid)' for the I386_* macros. */ ++ inferior_ptid = pid_to_ptid (detached_pid); ++ ++ i386_detach_breakpoints (detached_pid); ++ ++ do_cleanups (old_chain); ++} + + + /* This function is called by libthread_db as part of its handling of +@@ -755,6 +808,42 @@ amd64_linux_siginfo_fixup (struct siginf + return 0; + } + ++static int (*amd64_linux_super_follow_fork) (struct target_ops *ops, ++ int follow_child); ++ ++/* We need to duplicate the LINUX_CHILD_FOLLOW_FORK behavior here and catch its ++ called DETACH_BREAKPOINTS to avoid corrupting our local registers mirror. */ ++ ++static int ++amd64_linux_follow_fork (struct target_ops *ops, int follow_child) ++{ ++ ptid_t last_ptid; ++ struct target_waitstatus last_status; ++ int has_vforked; ++ int parent_pid, child_pid; ++ ++ get_last_target_status (&last_ptid, &last_status); ++ has_vforked = (last_status.kind == TARGET_WAITKIND_VFORKED); ++ parent_pid = ptid_get_lwp (last_ptid); ++ if (parent_pid == 0) ++ parent_pid = ptid_get_pid (last_ptid); ++ child_pid = ptid_get_lwp (last_status.value.related_pid); ++ if (child_pid == 0) ++ child_pid = ptid_get_pid (last_status.value.related_pid); ++ ++ if (! follow_child) ++ { ++ amd64_linux_detach_breakpoints (child_pid); ++ } ++ else ++ { ++ if (! has_vforked) ++ amd64_linux_detach_breakpoints (child_pid); ++ } ++ ++ return (*amd64_linux_super_follow_fork) (ops, follow_child); ++} ++ + /* Provide a prototype to silence -Wmissing-prototypes. */ + void _initialize_amd64_linux_nat (void); + +@@ -791,6 +880,9 @@ _initialize_amd64_linux_nat (void) + linux_elfcore_write_prstatus = amd64_linux_elfcore_write_prstatus; + linux_elfcore_write_prfpreg = amd64_linux_elfcore_write_prfpreg; + ++ amd64_linux_super_follow_fork = t->to_follow_fork; ++ t->to_follow_fork = amd64_linux_follow_fork; ++ + /* Register the target. */ + linux_nat_add_target (t); + linux_nat_set_new_thread (t, amd64_linux_new_thread); +Index: gdb-6.8.50.20090209/gdb/config/i386/nm-i386.h +=================================================================== +--- gdb-6.8.50.20090209.orig/gdb/config/i386/nm-i386.h 2009-01-03 06:57:54.000000000 +0100 ++++ gdb-6.8.50.20090209/gdb/config/i386/nm-i386.h 2009-02-09 16:02:42.000000000 +0100 +@@ -120,6 +120,8 @@ extern int i386_stopped_by_watchpoint (v + + #endif /* I386_WATCHPOINTS_IN_TARGET_VECTOR */ + ++extern void i386_detach_breakpoints (int detached_pid); ++ + #endif /* I386_USE_GENERIC_WATCHPOINTS */ + + #endif /* NM_I386_H */ +Index: gdb-6.8.50.20090209/gdb/i386-linux-nat.c +=================================================================== +--- gdb-6.8.50.20090209.orig/gdb/i386-linux-nat.c 2009-01-03 06:57:51.000000000 +0100 ++++ gdb-6.8.50.20090209/gdb/i386-linux-nat.c 2009-02-09 16:02:42.000000000 +0100 +@@ -634,21 +634,42 @@ i386_linux_dr_set_control (unsigned long + ptid_t ptid; + + i386_linux_dr[DR_CONTROL] = control; +- ALL_LWPS (lp, ptid) +- i386_linux_dr_set (ptid, DR_CONTROL, control); ++ ++ /* I386_DETACH_BREAKPOINTS may need to reset the registers on single process ++ not listed for ALL_LWPS. */ ++ ++ if (ptid_get_lwp (inferior_ptid) == 0) ++ i386_linux_dr_set (inferior_ptid, DR_CONTROL, control); ++ else ++ { ++ struct lwp_info *lp; ++ ptid_t ptid; ++ ++ ALL_LWPS (lp, ptid) ++ i386_linux_dr_set (ptid, DR_CONTROL, control); ++ } + } + + void + i386_linux_dr_set_addr (int regnum, CORE_ADDR addr) + { +- struct lwp_info *lp; +- ptid_t ptid; +- + gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR); + + i386_linux_dr[DR_FIRSTADDR + regnum] = addr; +- ALL_LWPS (lp, ptid) +- i386_linux_dr_set (ptid, DR_FIRSTADDR + regnum, addr); ++ ++ /* I386_DETACH_BREAKPOINTS may need to reset the registers on single process ++ not listed for ALL_LWPS. */ ++ ++ if (ptid_get_lwp (inferior_ptid) == 0) ++ i386_linux_dr_set (inferior_ptid, DR_FIRSTADDR + regnum, addr); ++ else ++ { ++ struct lwp_info *lp; ++ ptid_t ptid; ++ ++ ALL_LWPS (lp, ptid) ++ i386_linux_dr_set (ptid, DR_FIRSTADDR + regnum, addr); ++ } + } + + void +@@ -673,6 +694,41 @@ i386_linux_new_thread (ptid_t ptid) + + i386_linux_dr_set (ptid, DR_CONTROL, i386_linux_dr[DR_CONTROL]); + } ++ ++/* TO_FOLLOW_FORK stores here the PID under DETACH_BREAKPOINTS for the child ++ process of traced FORK. We must clear such watchpoints only once during ++ DETACH_BREAKPOINTS. */ ++ ++static int i386_linux_detach_breakpoints_pid; ++ ++/* Remove a watchpoint that watched the memory region which starts at ++ address ADDR, whose length is LEN bytes, and for accesses of the ++ type TYPE. Return 0 on success, -1 on failure. */ ++int ++i386_linux_remove_watchpoint (CORE_ADDR addr, int len, int type) ++{ ++ if (ptid_get_pid (inferior_ptid) == i386_linux_detach_breakpoints_pid) ++ return 0; ++ /* FOLLOW-FORK-MODE CHILD runs later the CHILD with no restrictions. */ ++ i386_linux_detach_breakpoints_pid = 0; ++ ++ return i386_remove_watchpoint (addr, len, type); ++} ++ ++static void ++i386_linux_detach_breakpoints (int detached_pid) ++{ ++ struct cleanup *old_chain = save_inferior_ptid (); ++ int i; ++ ++ i386_linux_detach_breakpoints_pid = detached_pid; ++ /* Depend on `!is_lwp (inferior_ptid)' for the I386_* macros. */ ++ inferior_ptid = pid_to_ptid (detached_pid); ++ ++ i386_detach_breakpoints (detached_pid); ++ ++ do_cleanups (old_chain); ++} + + + /* Called by libthread_db. Returns a pointer to the thread local +@@ -812,6 +868,40 @@ i386_linux_child_post_startup_inferior ( + super_post_startup_inferior (ptid); + } + ++static int (*i386_linux_super_follow_fork) (struct target_ops *ops, ++ int follow_child); ++ ++/* We need to duplicate the LINUX_CHILD_FOLLOW_FORK behavior here and catch its ++ called DETACH_BREAKPOINTS to avoid corrupting our local registers mirror. */ ++ ++static int ++i386_linux_follow_fork (struct target_ops *ops, int follow_child) ++{ ++ ptid_t last_ptid; ++ struct target_waitstatus last_status; ++ int has_vforked; ++ int parent_pid, child_pid; ++ ++ get_last_target_status (&last_ptid, &last_status); ++ has_vforked = (last_status.kind == TARGET_WAITKIND_VFORKED); ++ parent_pid = ptid_get_lwp (last_ptid); ++ if (parent_pid == 0) ++ parent_pid = ptid_get_pid (last_ptid); ++ child_pid = ptid_get_pid (last_status.value.related_pid); ++ ++ if (! follow_child) ++ { ++ i386_linux_detach_breakpoints (child_pid); ++ } ++ else ++ { ++ if (! has_vforked) ++ i386_linux_detach_breakpoints (child_pid); ++ } ++ ++ return (*i386_linux_super_follow_fork) (ops, follow_child); ++} ++ + void + _initialize_i386_linux_nat (void) + { +@@ -833,6 +923,9 @@ _initialize_i386_linux_nat (void) + t->to_fetch_registers = i386_linux_fetch_inferior_registers; + t->to_store_registers = i386_linux_store_inferior_registers; + ++ i386_linux_super_follow_fork = t->to_follow_fork; ++ t->to_follow_fork = i386_linux_follow_fork; ++ + /* Register the target. */ + linux_nat_add_target (t); + linux_nat_set_new_thread (t, i386_linux_new_thread); +Index: gdb-6.8.50.20090209/gdb/i386-nat.c +=================================================================== +--- gdb-6.8.50.20090209.orig/gdb/i386-nat.c 2009-01-03 06:57:51.000000000 +0100 ++++ gdb-6.8.50.20090209/gdb/i386-nat.c 2009-02-09 16:02:42.000000000 +0100 +@@ -546,6 +546,17 @@ i386_remove_watchpoint (CORE_ADDR addr, + return retval; + } + ++void ++i386_detach_breakpoints (int detached_pid) ++{ ++ int i; ++ ++ /* Do not touch any DR_MIRROR or DR_CONTROL_MIRROR mirrors here. */ ++ I386_DR_LOW_SET_CONTROL (0); ++ ALL_DEBUG_REGISTERS(i) ++ I386_DR_LOW_RESET_ADDR (i); ++} ++ + /* Return non-zero if we can watch a memory region that starts at + address ADDR and whose length is LEN bytes. */ + +Index: gdb-6.8.50.20090209/gdb/ia64-linux-nat.c +=================================================================== +--- gdb-6.8.50.20090209.orig/gdb/ia64-linux-nat.c 2009-02-09 15:48:43.000000000 +0100 ++++ gdb-6.8.50.20090209/gdb/ia64-linux-nat.c 2009-02-09 16:02:42.000000000 +0100 +@@ -583,6 +583,12 @@ ia64_linux_insert_watchpoint (CORE_ADDR + return 0; + } + ++/* TO_FOLLOW_FORK stores here the PID under DETACH_BREAKPOINTS for the child ++ process of traced FORK. We must clear such watchpoints only once during ++ DETACH_BREAKPOINTS. */ ++ ++static int ia64_linux_detach_breakpoints_pid; ++ + static int + ia64_linux_remove_watchpoint (CORE_ADDR addr, int len, int type) + { +@@ -590,6 +596,11 @@ ia64_linux_remove_watchpoint (CORE_ADDR + long dbr_addr, dbr_mask; + int max_watchpoints = 4; + ++ if (ptid_get_pid (inferior_ptid) == ia64_linux_detach_breakpoints_pid) ++ return 0; ++ /* FOLLOW-FORK-MODE CHILD runs later the CHILD with no restrictions. */ ++ ia64_linux_detach_breakpoints_pid = 0; ++ + if (len <= 0 || !is_power_of_2 (len)) + return -1; + +@@ -617,6 +628,22 @@ ia64_linux_remove_watchpoint (CORE_ADDR + } + + static void ++ia64_linux_detach_breakpoints (int detached_pid) ++{ ++ int idx, i; ++ long dbr_addr, dbr_mask; ++ int max_watchpoints = 4; ++ ++ ia64_linux_detach_breakpoints_pid = detached_pid; ++ ++ /* Do not touch any DEBUG_REGISTERS mirrors here. */ ++ dbr_addr = 0; ++ dbr_mask = 0; ++ for (idx = 0; idx < max_watchpoints; idx++) ++ store_debug_register_pair (ptid_build (detached_pid, 0, 0), idx, &dbr_addr, &dbr_mask); ++} ++ ++static void + ia64_linux_new_thread (ptid_t ptid) + { + int i, any; +@@ -805,6 +832,40 @@ ia64_linux_xfer_partial (struct target_o + offset, len); + } + ++static int (*ia64_linux_super_follow_fork) (struct target_ops *ops, ++ int follow_child); ++ ++/* We need to duplicate the LINUX_CHILD_FOLLOW_FORK behavior here and catch its ++ called DETACH_BREAKPOINTS to avoid corrupting our local registers mirror. */ ++ ++int ++ia64_linux_follow_fork (struct target_ops *ops, int follow_child) ++{ ++ ptid_t last_ptid; ++ struct target_waitstatus last_status; ++ int has_vforked; ++ int parent_pid, child_pid; ++ ++ get_last_target_status (&last_ptid, &last_status); ++ has_vforked = (last_status.kind == TARGET_WAITKIND_VFORKED); ++ parent_pid = ptid_get_lwp (last_ptid); ++ if (parent_pid == 0) ++ parent_pid = ptid_get_pid (last_ptid); ++ child_pid = ptid_get_pid (last_status.value.related_pid); ++ ++ if (! follow_child) ++ { ++ ia64_linux_detach_breakpoints (child_pid); ++ } ++ else ++ { ++ if (! has_vforked) ++ ia64_linux_detach_breakpoints (child_pid); ++ } ++ ++ return (*ia64_linux_super_follow_fork) (ops, follow_child); ++} ++ + void _initialize_ia64_linux_nat (void); + + /* +@@ -899,6 +960,9 @@ _initialize_ia64_linux_nat (void) + t->to_insert_watchpoint = ia64_linux_insert_watchpoint; + t->to_remove_watchpoint = ia64_linux_remove_watchpoint; + ++ ia64_linux_super_follow_fork = t->to_follow_fork; ++ t->to_follow_fork = ia64_linux_follow_fork; ++ + /* Register the target. */ + linux_nat_add_target (t); + linux_nat_set_new_thread (t, ia64_linux_new_thread); +Index: gdb-6.8.50.20090209/gdb/ppc-linux-nat.c +=================================================================== +--- gdb-6.8.50.20090209.orig/gdb/ppc-linux-nat.c 2009-01-03 06:57:52.000000000 +0100 ++++ gdb-6.8.50.20090209/gdb/ppc-linux-nat.c 2009-02-09 16:02:42.000000000 +0100 +@@ -1118,6 +1118,12 @@ ppc_linux_insert_watchpoint (CORE_ADDR a + return 0; + } + ++/* TO_FOLLOW_FORK stores here the PID under DETACH_BREAKPOINTS for the child ++ process of traced FORK. We must clear such watchpoints only once during ++ DETACH_BREAKPOINTS. */ ++ ++static int ppc_linux_detach_breakpoints_pid; ++ + static int + ppc_linux_remove_watchpoint (CORE_ADDR addr, int len, int rw) + { +@@ -1125,6 +1131,11 @@ ppc_linux_remove_watchpoint (CORE_ADDR a + ptid_t ptid; + long dabr_value = 0; + ++ if (ptid_get_pid (inferior_ptid) == ppc_linux_detach_breakpoints_pid) ++ return 0; ++ /* FOLLOW-FORK-MODE CHILD runs later the CHILD with no restrictions. */ ++ ppc_linux_detach_breakpoints_pid = 0; ++ + saved_dabr_value = 0; + ALL_LWPS (lp, ptid) + if (ptrace (PTRACE_SET_DEBUGREG, TIDGET (ptid), 0, saved_dabr_value) < 0) +@@ -1138,6 +1149,15 @@ ppc_linux_new_thread (ptid_t ptid) + ptrace (PTRACE_SET_DEBUGREG, TIDGET (ptid), 0, saved_dabr_value); + } + ++static void ++ppc_linux_detach_breakpoints (int detached_pid) ++{ ++ ppc_linux_detach_breakpoints_pid = detached_pid; ++ ++ /* Do not touch the SAVED_DABR_VALUE mirror here. */ ++ ptrace (PTRACE_SET_DEBUGREG, detached_pid, 0, 0); ++} ++ + static int + ppc_linux_stopped_data_address (struct target_ops *target, CORE_ADDR *addr_p) + { +@@ -1318,6 +1338,40 @@ ppc_linux_read_description (struct targe + return isa205? tdesc_powerpc_isa205_32l : tdesc_powerpc_32l; + } + ++static int (*ppc_linux_super_follow_fork) (struct target_ops *ops, ++ int follow_child); ++ ++/* We need to duplicate the LINUX_CHILD_FOLLOW_FORK behavior here and catch its ++ called DETACH_BREAKPOINTS to avoid corrupting our local registers mirror. */ ++ ++int ++ppc_linux_follow_fork (struct target_ops *ops, int follow_child) ++{ ++ ptid_t last_ptid; ++ struct target_waitstatus last_status; ++ int has_vforked; ++ int parent_pid, child_pid; ++ ++ get_last_target_status (&last_ptid, &last_status); ++ has_vforked = (last_status.kind == TARGET_WAITKIND_VFORKED); ++ parent_pid = ptid_get_lwp (last_ptid); ++ if (parent_pid == 0) ++ parent_pid = ptid_get_pid (last_ptid); ++ child_pid = ptid_get_pid (last_status.value.related_pid); ++ ++ if (! follow_child) ++ { ++ ppc_linux_detach_breakpoints (child_pid); ++ } ++ else ++ { ++ if (! has_vforked) ++ ppc_linux_detach_breakpoints (child_pid); ++ } ++ ++ return (*ppc_linux_super_follow_fork) (ops, follow_child); ++} ++ + void _initialize_ppc_linux_nat (void); + + void +@@ -1343,6 +1397,9 @@ _initialize_ppc_linux_nat (void) + + t->to_read_description = ppc_linux_read_description; + ++ ppc_linux_super_follow_fork = t->to_follow_fork; ++ t->to_follow_fork = ppc_linux_follow_fork; ++ + /* Register the target. */ + linux_nat_add_target (t); + linux_nat_set_new_thread (t, ppc_linux_new_thread); +Index: gdb-6.8.50.20090209/gdb/s390-nat.c +=================================================================== +--- gdb-6.8.50.20090209.orig/gdb/s390-nat.c 2007-11-07 07:36:57.000000000 +0100 ++++ gdb-6.8.50.20090209/gdb/s390-nat.c 2009-02-09 16:02:42.000000000 +0100 +@@ -283,21 +283,15 @@ s390_stopped_by_watchpoint (void) + } + + static void +-s390_fix_watch_points (ptid_t ptid) ++s390_fix_watch_points_list (int tid, struct watch_area *area_list) + { +- int tid; +- + per_struct per_info; + ptrace_area parea; + + CORE_ADDR watch_lo_addr = (CORE_ADDR)-1, watch_hi_addr = 0; + struct watch_area *area; + +- tid = TIDGET (ptid); +- if (tid == 0) +- tid = PIDGET (ptid); +- +- for (area = watch_base; area; area = area->next) ++ for (area = area_list; area; area = area->next) + { + watch_lo_addr = min (watch_lo_addr, area->lo_addr); + watch_hi_addr = max (watch_hi_addr, area->hi_addr); +@@ -309,7 +303,7 @@ s390_fix_watch_points (ptid_t ptid) + if (ptrace (PTRACE_PEEKUSR_AREA, tid, &parea) < 0) + perror_with_name (_("Couldn't retrieve watchpoint status")); + +- if (watch_base) ++ if (area_list) + { + per_info.control_regs.bits.em_storage_alteration = 1; + per_info.control_regs.bits.storage_alt_space_ctl = 1; +@@ -326,6 +320,18 @@ s390_fix_watch_points (ptid_t ptid) + perror_with_name (_("Couldn't modify watchpoint status")); + } + ++static void ++s390_fix_watch_points (ptid_t ptid) ++{ ++ int tid; ++ ++ tid = TIDGET (ptid); ++ if (tid == 0) ++ tid = PIDGET (ptid); ++ ++ s390_fix_watch_points_list (tid, watch_base); ++} ++ + static int + s390_insert_watchpoint (CORE_ADDR addr, int len, int type) + { +@@ -347,6 +353,12 @@ s390_insert_watchpoint (CORE_ADDR addr, + return 0; + } + ++/* TO_FOLLOW_FORK stores here the PID under DETACH_BREAKPOINTS for the child ++ process of traced FORK. We must clear such watchpoints only once during ++ DETACH_BREAKPOINTS. */ ++ ++static int s390_detach_breakpoints_pid; ++ + static int + s390_remove_watchpoint (CORE_ADDR addr, int len, int type) + { +@@ -354,6 +366,11 @@ s390_remove_watchpoint (CORE_ADDR addr, + ptid_t ptid; + struct watch_area *area, **parea; + ++ if (ptid_get_pid (inferior_ptid) == s390_detach_breakpoints_pid) ++ return 0; ++ /* FOLLOW-FORK-MODE CHILD runs later the CHILD with no restrictions. */ ++ s390_detach_breakpoints_pid = 0; ++ + for (parea = &watch_base; *parea; parea = &(*parea)->next) + if ((*parea)->lo_addr == addr + && (*parea)->hi_addr == addr + len - 1) +@@ -361,8 +378,10 @@ s390_remove_watchpoint (CORE_ADDR addr, + + if (!*parea) + { ++#if 0 /* Red Hat fork/threads watchpoints changes may trigger it. */ + fprintf_unfiltered (gdb_stderr, + "Attempt to remove nonexistent watchpoint.\n"); ++#endif + return -1; + } + +@@ -375,6 +394,15 @@ s390_remove_watchpoint (CORE_ADDR addr, + return 0; + } + ++static void ++s390_detach_breakpoints (int detached_pid) ++{ ++ s390_detach_breakpoints_pid = detached_pid; ++ ++ /* Do not touch the WATCH_BASE here. */ ++ s390_fix_watch_points_list (detached_pid, NULL); ++} ++ + static int + s390_can_use_hw_breakpoint (int type, int cnt, int othertype) + { +@@ -387,6 +415,39 @@ s390_region_ok_for_hw_watchpoint (CORE_A + return 1; + } + ++static int (*s390_super_follow_fork) (struct target_ops *ops, int follow_child); ++ ++/* We need to duplicate the LINUX_CHILD_FOLLOW_FORK behavior here and catch its ++ called DETACH_BREAKPOINTS to avoid corrupting our local registers mirror. */ ++ ++int ++s390_follow_fork (struct target_ops *ops, int follow_child) ++{ ++ ptid_t last_ptid; ++ struct target_waitstatus last_status; ++ int has_vforked; ++ int parent_pid, child_pid; ++ ++ get_last_target_status (&last_ptid, &last_status); ++ has_vforked = (last_status.kind == TARGET_WAITKIND_VFORKED); ++ parent_pid = ptid_get_lwp (last_ptid); ++ if (parent_pid == 0) ++ parent_pid = ptid_get_pid (last_ptid); ++ child_pid = ptid_get_pid (last_status.value.related_pid); ++ ++ if (! follow_child) ++ { ++ s390_detach_breakpoints (child_pid); ++ } ++ else ++ { ++ if (! has_vforked) ++ s390_detach_breakpoints (child_pid); ++ } ++ ++ return (*s390_super_follow_fork) (ops, follow_child); ++} ++ + + void _initialize_s390_nat (void); + +@@ -410,6 +471,9 @@ _initialize_s390_nat (void) + t->to_insert_watchpoint = s390_insert_watchpoint; + t->to_remove_watchpoint = s390_remove_watchpoint; + ++ s390_super_follow_fork = t->to_follow_fork; ++ t->to_follow_fork = s390_follow_fork; ++ + /* Register the target. */ + linux_nat_add_target (t); + linux_nat_set_new_thread (t, s390_fix_watch_points); +Index: gdb-6.8.50.20090209/gdb/testsuite/gdb.threads/watchpoint-fork-forkoff.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8.50.20090209/gdb/testsuite/gdb.threads/watchpoint-fork-forkoff.c 2009-02-09 16:02:42.000000000 +0100 +@@ -0,0 +1,172 @@ ++/* Test case for forgotten hw-watchpoints after fork()-off of a process. ++ ++ Copyright 2008 ++ Free Software Foundation, Inc. ++ ++ This file is part of GDB. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place - Suite 330, ++ Boston, MA 02111-1307, USA. */ ++ ++#include ++#include ++ ++static void delay (void) ++{ ++ int i = usleep (1000000 / 100); ++ assert (i == 0 || errno == EINTR); ++} ++ ++#if defined FOLLOW_PARENT ++ ++static void forkoff (int nr) ++{ ++ pid_t child, pid_got; ++ int exit_code = 42 + nr; ++ int status, i; ++ ++ child = fork (); ++ switch (child) ++ { ++ case -1: ++ assert (0); ++ case 0: ++ printf ("child%d: %d\n", nr, (int) getpid ()); ++ /* Delay to get both the "child%d" and "parent%d" message printed without ++ a race breaking expect by its endless wait on `$gdb_prompt$': ++ Breakpoint 3, breakpoint () at ../../../gdb/testsuite/gdb.threads/watchpoint-fork.c:33 ++ 33 } ++ (gdb) parent2: 14223 */ ++ i = sleep (1); ++ assert (i == 0); ++ ++ /* We must not get caught here (against a forgotten breakpoint). */ ++ var++; ++ breakpoint (); ++ ++ _exit (exit_code); ++ default: ++ printf ("parent%d: %d\n", nr, (int) child); ++ /* Delay to get both the "child%d" and "parent%d" message printed, see ++ above. */ ++ i = sleep (1); ++ assert (i == 0); ++ ++ pid_got = wait (&status); ++ assert (pid_got == child); ++ assert (WIFEXITED (status)); ++ assert (WEXITSTATUS (status) == exit_code); ++ ++ /* We must get caught here (against a false watchpoint removal). */ ++ breakpoint (); ++ } ++} ++ ++#elif defined FOLLOW_CHILD ++ ++static volatile int usr1_got; ++ ++static void handler_usr1 (int signo) ++{ ++ usr1_got++; ++} ++ ++static void forkoff (int nr) ++{ ++ pid_t child; ++ int i, loop; ++ struct sigaction act, oldact; ++#ifdef THREAD ++ void *thread_result; ++#endif ++ ++ memset (&act, 0, sizeof act); ++ act.sa_flags = SA_RESTART; ++ act.sa_handler = handler_usr1; ++ sigemptyset (&act.sa_mask); ++ i = sigaction (SIGUSR1, &act, &oldact); ++ assert (i == 0); ++ ++ child = fork (); ++ switch (child) ++ { ++ case -1: ++ assert (0); ++ default: ++ printf ("parent%d: %d\n", nr, (int) child); ++ ++ /* Sleep for a while to possibly get incorrectly ATTACH_THREADed by GDB ++ tracing the child fork with no longer valid thread/lwp entries of the ++ parent. */ ++ ++ i = sleep (2); ++ assert (i == 0); ++ ++ /* We must not get caught here (against a forgotten breakpoint). */ ++ ++ var++; ++ breakpoint (); ++ ++#ifdef THREAD ++ /* And neither got caught our thread. */ ++ ++ step = 99; ++ i = pthread_join (thread, &thread_result); ++ assert (i == 0); ++ assert (thread_result == (void *) 99UL); ++#endif ++ ++ /* Be sure our child knows we did not get caught above. */ ++ ++ i = kill (child, SIGUSR1); ++ assert (i == 0); ++ ++ /* Sleep for a while to check GDB's `info threads' no longer tracks us in ++ the child fork. */ ++ ++ i = sleep (2); ++ assert (i == 0); ++ ++ _exit (0); ++ case 0: ++ printf ("child%d: %d\n", nr, (int) getpid ()); ++ ++ /* Let the parent signal us about its success. Be careful of races. */ ++ ++ for (loop = 0; loop < 1000; loop++) ++ { ++ /* Parent either died (and USR1_GOT is zero) or it succeeded. */ ++ if (kill (getppid (), 0) != 0) ++ break; ++ /* Parent succeeded? */ ++ if (usr1_got) ++ break; ++ ++ delay (); ++ } ++ assert (usr1_got); ++ ++ /* We must get caught here (against a false watchpoint removal). */ ++ ++ breakpoint (); ++ } ++ ++ i = sigaction (SIGUSR1, &oldact, NULL); ++ assert (i == 0); ++} ++ ++#else ++# error "!FOLLOW_PARENT && !FOLLOW_CHILD" ++#endif +Index: gdb-6.8.50.20090209/gdb/testsuite/gdb.threads/watchpoint-fork-mt.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8.50.20090209/gdb/testsuite/gdb.threads/watchpoint-fork-mt.c 2009-02-09 16:02:42.000000000 +0100 +@@ -0,0 +1,154 @@ ++/* Test case for forgotten hw-watchpoints after fork()-off of a process. ++ ++ Copyright 2008 ++ Free Software Foundation, Inc. ++ ++ This file is part of GDB. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place - Suite 330, ++ Boston, MA 02111-1307, USA. */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#define gettid() syscall (__NR_gettid) ++ ++/* Non-atomic `var++' should not hurt as we synchronize the threads by the STEP ++ variable. Hit-comments need to be duplicite there to catch both at-stops ++ and behind-stops, depending on the target. */ ++ ++static volatile int var; ++ ++static void dummy (void) ++{ ++} ++ ++static void breakpoint (void) ++{ ++} ++ ++/* Include here the functions: ++ static void forkoff (int nr); ++ static void delay (void); */ ++ ++static pthread_t thread; ++static volatile int step; ++#define THREAD ++ ++#include "watchpoint-fork-forkoff.c" ++ ++static void *start (void *arg) ++{ ++ if (step >= 3) ++ goto step_3; ++ ++ while (step != 1) ++ delay (); ++ ++ var++; /* validity-thread-B */ ++ dummy (); /* validity-thread-B */ ++ step = 2; ++ while (step != 3) ++ { ++ if (step == 99) ++ goto step_99; ++ delay (); ++ } ++ ++step_3: ++ if (step >= 5) ++ goto step_5; ++ ++ var++; /* after-fork1-B */ ++ dummy (); /* after-fork1-B */ ++ step = 4; ++ while (step != 5) ++ { ++ if (step == 99) ++ goto step_99; ++ delay (); ++ } ++ ++step_5: ++ var++; /* after-fork2-B */ ++ dummy (); /* after-fork2-B */ ++ return (void *) 5UL; ++ ++step_99: ++ /* We must not get caught here (against a forgotten breakpoint). */ ++ var++; ++ breakpoint (); ++ return (void *) 99UL; ++} ++ ++int main (void) ++{ ++ int i; ++ void *thread_result; ++ ++ setbuf (stdout, NULL); ++ printf ("main: %d\n", (int) gettid ()); ++ ++ /* General watchpoints validity. */ ++ var++; /* validity-first */ ++ dummy (); /* validity-first */ ++ ++ i = pthread_create (&thread, NULL, start, NULL); ++ assert (i == 0); ++ ++ var++; /* validity-thread-A */ ++ dummy (); /* validity-thread-A */ ++ step = 1; ++ while (step != 2) ++ delay (); ++ ++ /* Hardware watchpoints got disarmed here. */ ++ forkoff (1); ++ ++ var++; /* after-fork1-A */ ++ dummy (); /* after-fork1-A */ ++ step = 3; ++#ifdef FOLLOW_CHILD ++ /* Spawn new thread as it was deleted in the child of FORK. */ ++ i = pthread_create (&thread, NULL, start, NULL); ++ assert (i == 0); ++#endif ++ while (step != 4) ++ delay (); ++ ++ /* A sanity check for double hardware watchpoints removal. */ ++ forkoff (2); ++ ++ var++; /* after-fork2-A */ ++ dummy (); /* after-fork2-A */ ++ step = 5; ++#ifdef FOLLOW_CHILD ++ /* Spawn new thread as it was deleted in the child of FORK. */ ++ i = pthread_create (&thread, NULL, start, NULL); ++ assert (i == 0); ++#endif ++ ++ i = pthread_join (thread, &thread_result); ++ assert (i == 0); ++ assert (thread_result == (void *) 5UL); ++ ++ return 0; ++} +Index: gdb-6.8.50.20090209/gdb/testsuite/gdb.threads/watchpoint-fork.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8.50.20090209/gdb/testsuite/gdb.threads/watchpoint-fork.c 2009-02-09 16:02:42.000000000 +0100 +@@ -0,0 +1,56 @@ ++/* Test case for forgotten hw-watchpoints after fork()-off of a process. ++ ++ Copyright 2008 ++ Free Software Foundation, Inc. ++ ++ This file is part of GDB. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place - Suite 330, ++ Boston, MA 02111-1307, USA. */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++static volatile int var; ++ ++static void breakpoint (void) ++{ ++} ++ ++/* Include here the function: ++ static void forkoff (int nr); */ ++ ++#include "watchpoint-fork-forkoff.c" ++ ++int main (void) ++{ ++ setbuf (stdout, NULL); ++ printf ("main: %d\n", (int) getpid ()); ++ ++ /* General watchpoints validity. */ ++ var++; ++ /* Hardware watchpoints got disarmed here. */ ++ forkoff (1); ++ /* This watchpoint got lost before. */ ++ var++; ++ /* A sanity check for double hardware watchpoints removal. */ ++ forkoff (2); ++ var++; ++ ++ return 0; ++} +Index: gdb-6.8.50.20090209/gdb/testsuite/gdb.threads/watchpoint-fork.exp +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8.50.20090209/gdb/testsuite/gdb.threads/watchpoint-fork.exp 2009-02-09 16:02:42.000000000 +0100 +@@ -0,0 +1,140 @@ ++# Copyright 2008 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++# Test case for forgotten hw-watchpoints after fork()-off of a process. ++ ++proc test {type symbol} { ++ global objdir subdir srcdir ++ ++ global pf_prefix ++ set prefix_test $pf_prefix ++ lappend pf_prefix "$type:" ++ set prefix_mt $pf_prefix ++ ++ # no threads ++ ++ set pf_prefix $prefix_mt ++ lappend pf_prefix "singlethreaded:" ++ ++ set testfile watchpoint-fork ++ set srcfile ${testfile}.c ++ set binfile ${objdir}/${subdir}/${testfile} ++ ++ if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable "debug additional_flags=-D$symbol"] != "" } { ++ untested "Couldn't compile test program" ++ return -1 ++ } ++ ++ gdb_exit ++ gdb_start ++ gdb_reinitialize_dir $srcdir/$subdir ++ gdb_load ${binfile} ++ ++ gdb_test "set follow-fork-mode $type" ++ # Testcase uses it for the `follow-fork-mode child' type. ++ gdb_test "handle SIGUSR1 nostop noprint pass" ++ ++ if { ![runto_main] } then { ++ gdb_suppress_tests ++ return ++ } ++ ++ # Install the watchpoint only after getting into MAIN - workaround some PPC ++ # problem. ++ gdb_test "watch var" "atchpoint 2: var" "Set the watchpoint" ++ ++ # It is never hit but it should not be left over in the fork()ed-off child. ++ gdb_breakpoint "breakpoint" ++ ++ gdb_test "continue" \ ++ "atchpoint 2: var.*Old value = 0.*New value = 1.*forkoff *\\(1\\).*" "watchpoints work" ++ gdb_test "continue" \ ++ "reakpoint 3, breakpoint.*" "breakpoint after the first fork" ++ gdb_test "continue" \ ++ "atchpoint 2: var.*Old value = 1.*New value = 2.*forkoff *\\(2\\).*" "watchpoint after the first fork" ++ gdb_test "continue" \ ++ "reakpoint 3, breakpoint.*" "breakpoint after the second fork" ++ gdb_test "continue" \ ++ "atchpoint 2: var.*Old value = 2.*New value = 3.*return *0;" "watchpoint after the second fork" ++ gdb_test "continue" "Continuing..*Program exited normally." "finish" ++ ++ ++ # threads ++ ++ set pf_prefix $prefix_mt ++ lappend pf_prefix "multithreaded:" ++ ++ set testfile watchpoint-fork-mt ++ set srcfile ${testfile}.c ++ set binfile ${objdir}/${subdir}/${testfile} ++ ++ if { [gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable "debug additional_flags=-D$symbol"] != "" } { ++ untested "Couldn't compile test program" ++ return -1 ++ } ++ ++ gdb_exit ++ gdb_start ++ gdb_reinitialize_dir $srcdir/$subdir ++ gdb_load ${binfile} ++ ++ gdb_test "set follow-fork-mode $type" ++ # Testcase uses it for the `follow-fork-mode child' type. ++ gdb_test "handle SIGUSR1 nostop noprint pass" ++ ++ if { ![runto_main] } then { ++ gdb_suppress_tests ++ return ++ } ++ ++ # Install the watchpoint only after getting into MAIN - workaround some PPC ++ # problem. ++ gdb_test "watch var" "atchpoint 2: var" "Set the watchpoint" ++ ++ # It is never hit but it should not be left over in the fork()ed-off child. ++ gdb_breakpoint "breakpoint" ++ ++ gdb_test "continue" \ ++ "atchpoint 2: var.*Old value = 0.*New value = 1.*validity-first.*" "singlethread watchpoints work" ++ gdb_test "continue" \ ++ "atchpoint 2: var.*Old value = 1.*New value = 2.*validity-thread-A.*" "multithreaded watchpoints work at A" ++ gdb_test "continue" \ ++ "atchpoint 2: var.*Old value = 2.*New value = 3.*validity-thread-B.*" "multithreaded watchpoints work at B" ++ gdb_test "continue" \ ++ "reakpoint 3, breakpoint.*" "breakpoint (A) after the first fork" ++ gdb_test "continue" \ ++ "atchpoint 2: var.*Old value = 3.*New value = 4.*after-fork1-A.*" "watchpoint A after the first fork" ++ gdb_test "continue" \ ++ "atchpoint 2: var.*Old value = 4.*New value = 5.*after-fork1-B.*" "watchpoint B after the first fork" ++ gdb_test "continue" \ ++ "reakpoint 3, breakpoint.*" "breakpoint (A) after the second fork" ++ gdb_test "continue" \ ++ "atchpoint 2: var.*Old value = 5.*New value = 6.*after-fork2-A.*" "watchpoint A after the second fork" ++ gdb_test "continue" \ ++ "atchpoint 2: var.*Old value = 6.*New value = 7.*after-fork2-B.*" "watchpoint B after the second fork" ++ gdb_test "continue" "Continuing..*Program exited normally." "finish" ++ ++ ++ # cleanup ++ ++ set pf_prefix $prefix_test ++} ++ ++test parent FOLLOW_PARENT ++ ++# Only GNU/Linux is known to support `set follow-fork-mode child'. ++if {[istarget "*-*-linux*"]} { ++ test child FOLLOW_CHILD ++} +Index: gdb-6.8.50.20090209/gdb/doc/gdb.texinfo +=================================================================== +--- gdb-6.8.50.20090209.orig/gdb/doc/gdb.texinfo 2009-02-09 16:02:35.000000000 +0100 ++++ gdb-6.8.50.20090209/gdb/doc/gdb.texinfo 2009-02-09 16:02:42.000000000 +0100 +@@ -3588,6 +3588,14 @@ confident that no other thread can becom + software watchpoints as usual. However, @value{GDBN} may not notice + when a non-current thread's activity changes the expression. (Hardware + watchpoints, in contrast, watch an expression in all threads.) ++ ++Software watchpoints single-step the current thread to track the changes. ++Other threads are left freely running on @code{continue}; therefore, their ++changes cannot be caught. To get more reliable software watchpoints, please ++use @code{set scheduler-locking on}. The default for Red Hat/Fedora ++@value{GDBN} is @code{set scheduler-locking step}, which makes the software ++watchpoints safe for the @code{step} command, but not for the @code{continue} ++command. @xref{Thread Stops}. + @end quotation + + @xref{set remote hardware-watchpoint-limit}. +Index: gdb-6.8.50.20090209/gdb/config/i386/nm-linux.h +=================================================================== +--- gdb-6.8.50.20090209.orig/gdb/config/i386/nm-linux.h 2009-01-03 06:57:54.000000000 +0100 ++++ gdb-6.8.50.20090209/gdb/config/i386/nm-linux.h 2009-02-09 16:02:42.000000000 +0100 +@@ -46,6 +46,16 @@ extern void i386_linux_dr_reset_addr (in + extern unsigned long i386_linux_dr_get_status (void); + #define I386_DR_LOW_GET_STATUS() \ + i386_linux_dr_get_status () ++ ++/* Remove a watchpoint that watched the memory region which starts at ++ * address ADDR, whose length is LEN bytes, and for accesses of the ++ * type TYPE. Return 0 on success, -1 on failure. */ ++extern int i386_linux_remove_watchpoint (CORE_ADDR addr, int len, int type); ++ ++/* Override basic i386 macros for watchpoint and hardware breakpoint ++ insertion/removal to support threads. */ ++#define target_remove_watchpoint(addr, len, type) \ ++ i386_linux_remove_watchpoint (addr, len, type) + + + #ifdef HAVE_PTRACE_GETFPXREGS +Index: gdb-6.8.50.20090209/gdb/config/i386/nm-linux64.h +=================================================================== +--- gdb-6.8.50.20090209.orig/gdb/config/i386/nm-linux64.h 2009-01-03 06:57:54.000000000 +0100 ++++ gdb-6.8.50.20090209/gdb/config/i386/nm-linux64.h 2009-02-09 16:02:42.000000000 +0100 +@@ -51,4 +51,14 @@ extern unsigned long amd64_linux_dr_get_ + #define I386_DR_LOW_GET_STATUS() \ + amd64_linux_dr_get_status () + ++/* Remove a watchpoint that watched the memory region which starts at ++ * address ADDR, whose length is LEN bytes, and for accesses of the ++ * type TYPE. Return 0 on success, -1 on failure. */ ++extern int amd64_linux_remove_watchpoint (CORE_ADDR addr, int len, int type); ++ ++/* Override basic amd64 macros for watchpoint and hardware breakpoint ++ insertion/removal to support threads. */ ++#define target_remove_watchpoint(addr, len, type) \ ++ amd64_linux_remove_watchpoint (addr, len, type) ++ + #endif /* nm-linux64.h */ +Index: gdb-6.8.50.20090209/gdb/target.h +=================================================================== +--- gdb-6.8.50.20090209.orig/gdb/target.h 2009-02-09 15:49:25.000000000 +0100 ++++ gdb-6.8.50.20090209/gdb/target.h 2009-02-09 16:02:42.000000000 +0100 +@@ -1113,7 +1113,9 @@ extern char *normal_pid_to_str (ptid_t p + #ifndef target_insert_watchpoint + #define target_insert_watchpoint(addr, len, type) \ + (*current_target.to_insert_watchpoint) (addr, len, type) ++#endif + ++#ifndef target_remove_watchpoint + #define target_remove_watchpoint(addr, len, type) \ + (*current_target.to_remove_watchpoint) (addr, len, type) + #endif diff --git a/gdb-6.6-readline-system.patch b/gdb-6.6-readline-system.patch new file mode 100644 index 0000000..02901e7 --- /dev/null +++ b/gdb-6.6-readline-system.patch @@ -0,0 +1,116 @@ +2007-10-16 Jan Kratochvil + + Port to GDB-6.7. + +Index: gdb-6.7/gdb/doc/Makefile.in +=================================================================== +--- gdb-6.7.orig/gdb/doc/Makefile.in 2007-07-26 12:34:00.000000000 +0200 ++++ gdb-6.7/gdb/doc/Makefile.in 2007-10-16 16:31:08.000000000 +0200 +@@ -109,9 +109,7 @@ DVIPS = dvips + GDB_DOC_SOURCE_INCLUDES = \ + $(srcdir)/fdl.texi \ + $(srcdir)/gpl.texi \ +- $(srcdir)/agentexpr.texi \ +- $(READLINE_DIR)/rluser.texi \ +- $(READLINE_DIR)/inc-hist.texinfo ++ $(srcdir)/agentexpr.texi + GDB_DOC_BUILD_INCLUDES = \ + gdb-cfg.texi \ + GDBvn.texi +Index: gdb-6.7/gdb/doc/gdb.texinfo +=================================================================== +--- gdb-6.7.orig/gdb/doc/gdb.texinfo 2007-10-16 16:19:19.000000000 +0200 ++++ gdb-6.7/gdb/doc/gdb.texinfo 2007-10-16 16:32:10.000000000 +0200 +@@ -158,8 +158,8 @@ software in general. We will miss him. + + * GDB Bugs:: Reporting bugs in @value{GDBN} + +-* Command Line Editing:: Command Line Editing +-* Using History Interactively:: Using History Interactively ++* Command Line Editing: (rluserman). Command Line Editing ++* Using History Interactively: (history). Using History Interactively + * Formatting Documentation:: How to format and print @value{GDBN} documentation + * Installing GDB:: Installing GDB + * Maintenance Commands:: Maintenance Commands +@@ -15533,7 +15533,7 @@ Disable command line editing. + Show whether command line editing is enabled. + @end table + +-@xref{Command Line Editing}, for more details about the Readline ++@xref{Command Line Editing, , , rluserman, GNU Readline Library}, for more details about the Readline + interface. Users unfamiliar with @sc{gnu} Emacs or @code{vi} are + encouraged to read that chapter. + +@@ -15548,7 +15548,8 @@ history facility. + + @value{GDBN} uses the @sc{gnu} History library, a part of the Readline + package, to provide the history facility. @xref{Using History +-Interactively}, for the detailed description of the History library. ++Interactively, , , history, GNU History Library}, for the detailed description ++of the History library. + + To issue a command to @value{GDBN} without affecting certain aspects of + the state which is seen by users, prefix it with @samp{server } +@@ -15600,7 +15601,7 @@ This defaults to the value of the enviro + @end table + + History expansion assigns special meaning to the character @kbd{!}. +-@xref{Event Designators}, for more details. ++@xref{Event Designators, , , history, GNU History Library}, for more details. + + @cindex history expansion, turn on/off + Since @kbd{!} is also the logical not operator in C, history expansion +@@ -16660,7 +16661,8 @@ Indicates the current program counter ad + @cindex TUI key bindings + + The TUI installs several key bindings in the readline keymaps +-(@pxref{Command Line Editing}). The following key bindings ++(@pxref{Command Line Editing, , , rluserman, GNU Readline Library}). ++The following key bindings + are installed for both TUI mode and the @value{GDBN} standard mode. + + @table @kbd +@@ -21937,15 +21939,6 @@ Such guesses are usually wrong. Even we + things without first using the debugger to find the facts. + @end itemize + +-@c The readline documentation is distributed with the readline code +-@c and consists of the two following files: +-@c rluser.texinfo +-@c inc-hist.texinfo +-@c Use -I with makeinfo to point to the appropriate directory, +-@c environment var TEXINPUTS with TeX. +-@include rluser.texi +-@include inc-hist.texinfo +- + + @node Formatting Documentation + @appendix Formatting Documentation +@@ -22115,9 +22108,6 @@ source for the @samp{-liberty} free soft + @item gdb-@value{GDBVN}/opcodes + source for the library of opcode tables and disassemblers + +-@item gdb-@value{GDBVN}/readline +-source for the @sc{gnu} command-line interface +- + @item gdb-@value{GDBVN}/glob + source for the @sc{gnu} filename pattern-matching subroutine + +@@ -22149,7 +22139,7 @@ where @var{host} is an identifier such a + correct value by examining your system.) + + Running @samp{configure @var{host}} and then running @code{make} builds the +-@file{bfd}, @file{readline}, @file{mmalloc}, and @file{libiberty} ++@file{bfd}, @file{mmalloc}, and @file{libiberty} + libraries, then @code{gdb} itself. The configured source files, and the + binaries, are left in the corresponding source directories. + +@@ -22175,7 +22165,7 @@ source tree, the @file{gdb-@var{version- + that subdirectory. That is usually not what you want. In particular, + if you run the first @file{configure} from the @file{gdb} subdirectory + of the @file{gdb-@var{version-number}} directory, you will omit the +-configuration of @file{bfd}, @file{readline}, and other sibling ++configuration of @file{bfd}, and other sibling + directories of the @file{gdb} subdirectory. This leads to build errors + about missing include files such as @file{bfd/bfd.h}. + diff --git a/gdb-6.6-scheduler_locking-step-is-default.patch b/gdb-6.6-scheduler_locking-step-is-default.patch new file mode 100644 index 0000000..f1053e6 --- /dev/null +++ b/gdb-6.6-scheduler_locking-step-is-default.patch @@ -0,0 +1,41 @@ +Index: gdb-6.8.50.20081128/gdb/infrun.c +=================================================================== +--- gdb-6.8.50.20081128.orig/gdb/infrun.c 2008-12-09 15:56:16.000000000 +0100 ++++ gdb-6.8.50.20081128/gdb/infrun.c 2008-12-09 15:56:59.000000000 +0100 +@@ -931,7 +931,7 @@ static const char *scheduler_enums[] = { + schedlock_step, + NULL + }; +-static const char *scheduler_mode = schedlock_off; ++static const char *scheduler_mode = schedlock_step; + static void + show_scheduler_mode (struct ui_file *file, int from_tty, + struct cmd_list_element *c, const char *value) +Index: gdb-6.8.50.20081128/gdb/testsuite/gdb.mi/mi-console.exp +=================================================================== +--- gdb-6.8.50.20081128.orig/gdb/testsuite/gdb.mi/mi-console.exp 2008-08-06 14:52:08.000000000 +0200 ++++ gdb-6.8.50.20081128/gdb/testsuite/gdb.mi/mi-console.exp 2008-12-09 15:59:34.000000000 +0100 +@@ -47,6 +47,9 @@ if { [gdb_compile "${srcdir}/${subdir}/ + + mi_run_to_main + ++# thread-id=\"all\" vs. thread-id=\"1\" below: ++mi_gdb_test "210-gdb-set scheduler-locking off" "210\\^done" "set scheduler-locking off" ++ + # Next over the hello() call which will produce lots of output + mi_gdb_test "220-exec-next" \ + "220\\^running(\r\n\\*running,thread-id=\"all\")?" \ +Index: gdb-6.8.50.20081128/gdb/testsuite/gdb.mi/mi2-console.exp +=================================================================== +--- gdb-6.8.50.20081128.orig/gdb/testsuite/gdb.mi/mi2-console.exp 2008-08-06 14:52:08.000000000 +0200 ++++ gdb-6.8.50.20081128/gdb/testsuite/gdb.mi/mi2-console.exp 2008-12-09 16:00:33.000000000 +0100 +@@ -47,6 +47,9 @@ if { [gdb_compile "${srcdir}/${subdir}/ + + mi_run_to_main + ++# thread-id=\"all\" vs. thread-id=\"1\" below: ++mi_gdb_test "210-gdb-set scheduler-locking off" "210\\^done" "set scheduler-locking off" ++ + # Next over the hello() call which will produce lots of output + send_gdb "220-exec-next\n" + gdb_expect { diff --git a/gdb-6.6-scheduler_locking-step-sw-watchpoints2.patch b/gdb-6.6-scheduler_locking-step-sw-watchpoints2.patch new file mode 100644 index 0000000..cdf9225 --- /dev/null +++ b/gdb-6.6-scheduler_locking-step-sw-watchpoints2.patch @@ -0,0 +1,202 @@ +2007-06-25 Jan Kratochvil + + * inferior.h (enum resume_step): New definition. + (resume): Change STEP parameter type to ENUM RESUME_STEP. + * infrun.c (resume): Likewise. Extend debug printing of the STEP + parameter. Lock the scheduler only for intentional stepping. + (proceed): Replace the variable ONESTEP with tristate RESUME_STEP. + Set the third RESUME_STEP state according to BPSTAT_SHOULD_STEP. + (currently_stepping): Change the return type to ENUM RESUME_STEP. + Return RESUME_STEP_NEEDED if it is just due to BPSTAT_SHOULD_STEP. + * linux-nat.c (select_singlestep_lwp_callback): Do not focus on + the software watchpoint events. + * linux-nat.h (struct lwp_info): Redeclare STEP as ENUM RESUME_STEP. + +2007-10-19 Jan Kratochvil + + * infrun.c (proceed): RESUME_STEP initialized for non-stepping. + RESUME_STEP set according to STEP only at the end of the function. + +2008-02-24 Jan Kratochvil + + Port to GDB-6.8pre. + +Index: gdb-6.8.50.20081209/gdb/inferior.h +=================================================================== +--- gdb-6.8.50.20081209.orig/gdb/inferior.h 2008-11-20 01:35:23.000000000 +0100 ++++ gdb-6.8.50.20081209/gdb/inferior.h 2008-12-10 01:22:23.000000000 +0100 +@@ -168,7 +168,15 @@ extern void reopen_exec_file (void); + /* The `resume' routine should only be called in special circumstances. + Normally, use `proceed', which handles a lot of bookkeeping. */ + +-extern void resume (int, enum target_signal); ++enum resume_step ++ { ++ /* currently_stepping () should return non-zero for non-continue. */ ++ RESUME_STEP_CONTINUE = 0, ++ RESUME_STEP_USER, /* Stepping is intentional by the user. */ ++ RESUME_STEP_NEEDED /* Stepping only for software watchpoints. */ ++ }; ++ ++extern void resume (enum resume_step, enum target_signal); + + /* From misc files */ + +Index: gdb-6.8.50.20081209/gdb/infrun.c +=================================================================== +--- gdb-6.8.50.20081209.orig/gdb/infrun.c 2008-12-02 20:20:23.000000000 +0100 ++++ gdb-6.8.50.20081209/gdb/infrun.c 2008-12-10 01:23:46.000000000 +0100 +@@ -73,7 +73,7 @@ static int follow_fork (void); + static void set_schedlock_func (char *args, int from_tty, + struct cmd_list_element *c); + +-static int currently_stepping (struct thread_info *tp); ++static enum resume_step currently_stepping (struct thread_info *tp); + + static int currently_stepping_callback (struct thread_info *tp, void *data); + +@@ -961,7 +961,7 @@ set_schedlock_func (char *args, int from + STEP nonzero if we should step (zero to continue instead). + SIG is the signal to give the inferior (zero for none). */ + void +-resume (int step, enum target_signal sig) ++resume (enum resume_step step, enum target_signal sig) + { + int should_resume = 1; + struct cleanup *old_cleanups = make_cleanup (resume_cleanups, 0); +@@ -975,10 +975,12 @@ resume (int step, enum target_signal sig + QUIT; + + if (debug_infrun) +- fprintf_unfiltered (gdb_stdlog, +- "infrun: resume (step=%d, signal=%d), " +- "trap_expected=%d\n", +- step, sig, tp->trap_expected); ++ fprintf_unfiltered (gdb_stdlog, "infrun: resume (step=%s, signal=%d), " ++ "trap_expected=%d\n", ++ (step == RESUME_STEP_CONTINUE ? "RESUME_STEP_CONTINUE" ++ : (step == RESUME_STEP_USER ? "RESUME_STEP_USER" ++ : "RESUME_STEP_NEEDED")), ++ sig, tp->trap_expected); + + /* Some targets (e.g. Solaris x86) have a kernel bug when stepping + over an instruction that causes a page fault without triggering +@@ -1127,9 +1129,10 @@ a command like `return' or `jump' to con + individually. */ + resume_ptid = inferior_ptid; + } +- else if ((scheduler_mode == schedlock_on) ++ else if (scheduler_mode == schedlock_on + || (scheduler_mode == schedlock_step +- && (step || singlestep_breakpoints_inserted_p))) ++ && (step == RESUME_STEP_USER ++ || singlestep_breakpoints_inserted_p))) + { + /* User-settable 'scheduler' mode requires solo thread resume. */ + resume_ptid = inferior_ptid; +@@ -1302,7 +1305,7 @@ proceed (CORE_ADDR addr, enum target_sig + struct gdbarch *gdbarch = get_regcache_arch (regcache); + struct thread_info *tp; + CORE_ADDR pc = regcache_read_pc (regcache); +- int oneproc = 0; ++ enum resume_step resume_step = RESUME_STEP_CONTINUE; + + if (step > 0) + step_start_function = find_pc_function (pc); +@@ -1322,13 +1325,13 @@ proceed (CORE_ADDR addr, enum target_sig + actually be executing the breakpoint insn anyway. + We'll be (un-)executing the previous instruction. */ + +- oneproc = 1; ++ resume_step = RESUME_STEP_USER; + else if (gdbarch_single_step_through_delay_p (gdbarch) + && gdbarch_single_step_through_delay (gdbarch, + get_current_frame ())) + /* We stepped onto an instruction that needs to be stepped + again before re-inserting the breakpoint, do so. */ +- oneproc = 1; ++ resume_step = RESUME_STEP_USER; + } + else + { +@@ -1359,13 +1362,13 @@ proceed (CORE_ADDR addr, enum target_sig + is required it returns TRUE and sets the current thread to + the old thread. */ + if (prepare_to_proceed (step)) +- oneproc = 1; ++ resume_step = RESUME_STEP_USER; + } + + /* prepare_to_proceed may change the current thread. */ + tp = inferior_thread (); + +- if (oneproc) ++ if (resume_step == RESUME_STEP_USER) + { + tp->trap_expected = 1; + /* If displaced stepping is enabled, we can step over the +@@ -1451,8 +1454,13 @@ proceed (CORE_ADDR addr, enum target_sig + /* Reset to normal state. */ + init_infwait_state (); + ++ if (step) ++ resume_step = RESUME_STEP_USER; ++ if (resume_step == RESUME_STEP_CONTINUE && bpstat_should_step ()) ++ resume_step = RESUME_STEP_NEEDED; ++ + /* Resume inferior. */ +- resume (oneproc || step || bpstat_should_step (), tp->stop_signal); ++ resume (resume_step, tp->stop_signal); + + /* Wait for it to stop (if not standalone) + and in any case decode why it stopped, and act accordingly. */ +@@ -3690,10 +3698,16 @@ currently_stepping_callback (struct thre + return tp != data && currently_stepping_thread (tp); + } + +-static int ++static enum resume_step + currently_stepping (struct thread_info *tp) + { +- return currently_stepping_thread (tp) || bpstat_should_step (); ++ if (currently_stepping_thread (tp)) ++ return RESUME_STEP_USER; ++ ++ if (bpstat_should_step ()) ++ return RESUME_STEP_NEEDED; ++ ++ return RESUME_STEP_CONTINUE; + } + + /* Inferior has stepped into a subroutine call with source code that +Index: gdb-6.8.50.20081209/gdb/linux-nat.c +=================================================================== +--- gdb-6.8.50.20081209.orig/gdb/linux-nat.c 2008-12-02 08:57:36.000000000 +0100 ++++ gdb-6.8.50.20081209/gdb/linux-nat.c 2008-12-10 01:22:23.000000000 +0100 +@@ -2343,7 +2343,10 @@ count_events_callback (struct lwp_info * + static int + select_singlestep_lwp_callback (struct lwp_info *lp, void *data) + { +- if (lp->step && lp->status != 0) ++ /* We do not focus on software watchpoints as we would not catch ++ STEPPING_PAST_SINGLESTEP_BREAKPOINT breakpoints in some other thread ++ as they would remain pending due to `Push back breakpoint for %s'. */ ++ if (lp->step == RESUME_STEP_USER && lp->status != 0) + return 1; + else + return 0; +Index: gdb-6.8.50.20081209/gdb/linux-nat.h +=================================================================== +--- gdb-6.8.50.20081209.orig/gdb/linux-nat.h 2008-07-27 23:12:40.000000000 +0200 ++++ gdb-6.8.50.20081209/gdb/linux-nat.h 2008-12-10 01:22:23.000000000 +0100 +@@ -55,8 +55,8 @@ struct lwp_info + /* If non-zero, a pending wait status. */ + int status; + +- /* Non-zero if we were stepping this LWP. */ +- int step; ++ /* The kind of stepping of this LWP. */ ++ enum resume_step step; + + /* Non-zero si_signo if this LWP stopped with a trap. si_addr may + be the address of a hardware watchpoint. */ diff --git a/gdb-6.6-step-thread-exit.patch b/gdb-6.6-step-thread-exit.patch new file mode 100644 index 0000000..142c77d --- /dev/null +++ b/gdb-6.6-step-thread-exit.patch @@ -0,0 +1,61 @@ +Index: gdb-6.8.50.20090226/gdb/linux-nat.c +=================================================================== +--- gdb-6.8.50.20090226.orig/gdb/linux-nat.c 2009-02-27 00:04:35.000000000 +0100 ++++ gdb-6.8.50.20090226/gdb/linux-nat.c 2009-02-27 07:51:44.000000000 +0100 +@@ -1790,15 +1790,17 @@ resume_set_callback (struct lwp_info *lp + + static void + linux_nat_resume (struct target_ops *ops, +- ptid_t ptid, int step, enum target_signal signo) ++ ptid_t ptid, int step_int, enum target_signal signo) + { + struct lwp_info *lp; + int resume_all; ++ enum resume_step step = step_int; + + if (debug_linux_nat) + fprintf_unfiltered (gdb_stdlog, + "LLR: Preparing to %s %s, %s, inferior_ptid %s\n", +- step ? "step" : "resume", ++ (step == RESUME_STEP_NEEDED ++ ? "needed" : (step ? "step" : "resume")), + target_pid_to_str (ptid), + signo ? strsignal (signo) : "0", + target_pid_to_str (inferior_ptid)); +@@ -2740,6 +2742,9 @@ linux_nat_filter_event (int lwpid, int s + /* Check if the thread has exited. */ + if ((WIFEXITED (status) || WIFSIGNALED (status)) && num_lwps > 1) + { ++ enum resume_step step = lp->step; ++ pid_t pid = GET_PID (lp->ptid); ++ + /* If this is the main thread, we must stop all threads and + verify if they are still alive. This is because in the nptl + thread model, there is no signal issued for exiting LWPs +@@ -2763,6 +2768,26 @@ linux_nat_filter_event (int lwpid, int s + + exit_lwp (lp); + ++ if (step == RESUME_STEP_USER) ++ { ++ /* Now stop the closest LWP's ... */ ++ lp = find_lwp_pid (pid_to_ptid (pid)); ++ if (!lp) ++ lp = lwp_list; ++ gdb_assert (lp != NULL); ++ errno = 0; ++ ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, ++ (void *) (unsigned long) SIGSTOP); ++ if (debug_linux_nat) ++ fprintf_unfiltered (gdb_stdlog, ++ "PTRACE_CONT %s, 0, 0 (%s)\n", ++ target_pid_to_str (lp->ptid), ++ errno ? safe_strerror (errno) ++ : "OK"); ++ /* Avoid the silent `delayed SIGSTOP' handling. */ ++ lp->signalled = 0; ++ } ++ + /* If there is at least one more LWP, then the exit signal was + not the end of the debugged application and should be + ignored. */ diff --git a/gdb-6.6-testsuite-timeouts.patch b/gdb-6.6-testsuite-timeouts.patch new file mode 100644 index 0000000..1166ef0 --- /dev/null +++ b/gdb-6.6-testsuite-timeouts.patch @@ -0,0 +1,42 @@ +--- ./gdb/testsuite/gdb.base/annota1.exp 10 Jan 2007 03:23:04 -0000 1.23 ++++ ./gdb/testsuite/gdb.base/annota1.exp 10 May 2007 12:54:11 -0000 +@@ -57,6 +57,8 @@ if [target_info exists gdb_stub] { + gdb_step_for_stub; + } + ++gdb_test "set breakpoint pending off" "" "Avoid lockup on nonexisting functions" ++ + # + # the line at which break main will put the breakpoint + # +--- ./gdb/testsuite/gdb.base/annota3.exp 9 Jan 2007 17:59:09 -0000 1.12 ++++ ./gdb/testsuite/gdb.base/annota3.exp 10 May 2007 12:54:11 -0000 +@@ -56,6 +56,8 @@ if [target_info exists gdb_stub] { + gdb_step_for_stub; + } + ++gdb_test "set breakpoint pending off" "" "Avoid lockup on nonexisting functions" ++ + # + # the line at which break main will put the breakpoint + # +--- gdb-6.6/gdb/testsuite/gdb.threads/step-thread-exit.exp-orig 2007-05-10 15:03:15.000000000 +0200 ++++ gdb-6.6/gdb/testsuite/gdb.threads/step-thread-exit.exp 2007-05-10 15:04:24.000000000 +0200 +@@ -58,6 +58,9 @@ gdb_test "continue" "Break.*thread_funct + # thread to be stopped and a message printed to tell us we have stepped + # over the thread exit. + set test "step over thread exit 1" ++# ppc64 is currently failing: ++set timeout_old $timeout ++set timeout 60 + gdb_test_multiple "next" "$test" { + -re "\}.*$gdb_prompt $" { + send_gdb "next\n" +@@ -71,6 +74,7 @@ gdb_test_multiple "next" "$test" { + exp_continue + } + } ++set timeout $timeout_old + + # Without this fixup we could end up in: + # #0 0x00110416 in __kernel_vsyscall () diff --git a/gdb-6.6-threads-static-test.patch b/gdb-6.6-threads-static-test.patch new file mode 100644 index 0000000..e8741a8 --- /dev/null +++ b/gdb-6.6-threads-static-test.patch @@ -0,0 +1,25 @@ +--- gdb-6.6/gdb/testsuite/gdb.threads/staticthreads.exp-orig 2005-04-30 21:56:47.000000000 +0200 ++++ gdb-6.6/gdb/testsuite/gdb.threads/staticthreads.exp 2008-01-11 14:30:15.000000000 +0100 +@@ -44,9 +44,21 @@ gdb_load ${binfile} + gdb_test "set print sevenbit-strings" "" + + ++runto_main ++ ++# See if we get excessive LWP there (patched glibc with unpatched GDB): ++# * 2 Thread 135661664 (LWP 3856) main () at threadloop.c:41 ++# 1 process 3856 main () at threadloop.c:41 ++ ++set test "info threads on start" ++gdb_test_multiple "info threads" "$test" { ++ -re "^info threads\r?\n\[^\r\n\]* Thread \[^\r\n\]*\r?\n$gdb_prompt" { ++ pass "$test" ++ } ++} ++ + # See if the static multi-threaded program runs. + +-runto_main + gdb_test "break sem_post" + set test "Continue to main's call of sem_post" + gdb_test_multiple "continue" "$test" { diff --git a/gdb-6.7-bz426600-DW_TAG_interface_type-fix.patch b/gdb-6.7-bz426600-DW_TAG_interface_type-fix.patch new file mode 100644 index 0000000..f99486c --- /dev/null +++ b/gdb-6.7-bz426600-DW_TAG_interface_type-fix.patch @@ -0,0 +1,41 @@ +Original patch was: +http://sourceware.org/ml/gdb-patches/2007-12/msg00397.html +http://sourceware.org/ml/gdb-cvs/2007-12/msg00123.html + +extended for the RHEL safety: + +2007-12-28 Jan Kratochvil + + * dwarf2read.c (fixup_partial_die): Provide full + `DW_TAG_class_type'-type backing for `DW_TAG_interface_type', even for + namespaces which should not apply for Java `DW_TAG_interface_type'. + +2008-02-24 Jan Kratochvil + + Port to GDB-6.8pre. + +Index: ./gdb/dwarf2read.c +=================================================================== +RCS file: /cvs/src/src/gdb/dwarf2read.c,v +retrieving revision 1.245 +diff -u -p -r1.245 dwarf2read.c +--- ./gdb/dwarf2read.c 26 Dec 2007 12:36:18 -0000 1.245 ++++ ./gdb/dwarf2read.c 27 Dec 2007 23:25:49 -0000 +@@ -5887,7 +5887,8 @@ fixup_partial_die (struct partial_die_in + + /* Set default names for some unnamed DIEs. */ + if (part_die->name == NULL && (part_die->tag == DW_TAG_structure_type +- || part_die->tag == DW_TAG_class_type)) ++ || part_die->tag == DW_TAG_class_type ++ || part_die->tag == DW_TAG_interface_type)) + part_die->name = "(anonymous class)"; + + if (part_die->name == NULL && part_die->tag == DW_TAG_namespace) +@@ -5895,6 +5896,7 @@ fixup_partial_die (struct partial_die_in + + if (part_die->tag == DW_TAG_structure_type + || part_die->tag == DW_TAG_class_type ++ || part_die->tag == DW_TAG_interface_type + || part_die->tag == DW_TAG_union_type) + guess_structure_name (part_die, cu); + } diff --git a/gdb-6.7-bz426600-DW_TAG_interface_type-test.patch b/gdb-6.7-bz426600-DW_TAG_interface_type-test.patch new file mode 100644 index 0000000..2e344ca --- /dev/null +++ b/gdb-6.7-bz426600-DW_TAG_interface_type-test.patch @@ -0,0 +1,710 @@ +http://sourceware.org/ml/gdb-patches/2007-12/msg00397.html + +2007-12-22 Jan Kratochvil + + * gdb.arch/i386-interface.S, gdb.arch/i386-interface.exp: New files. + +2008-03-02 Jan Kratochvil + + * gdb.arch/i386-interface.exp: Fix a testcase race. + +--- /dev/null 1 Jan 1970 00:00:00 -0000 ++++ ./gdb/testsuite/gdb.arch/i386-interface.S 22 Dec 2007 19:07:28 -0000 +@@ -0,0 +1,628 @@ ++/* Copyright 2007 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++ Please email any bugs, comments, and/or additions to this file to: ++ bug-gdb@gnu.org ++ ++ This file is part of the gdb testsuite. ++ ++ This file was produced by: ++ $ gcj -S interface.java -ggdb2 -Wall -m32 ++ from the .java file: ++ interface Interface ++ { ++ } ++ class Class implements Interface ++ { ++ } ++*/ ++ ++ .file "cc28Pp2B.jar" ++ .section .debug_abbrev,"",@progbits ++.Ldebug_abbrev0: ++ .section .debug_info,"",@progbits ++.Ldebug_info0: ++ .section .debug_line,"",@progbits ++.Ldebug_line0: ++ .text ++.Ltext0: ++ .local _MT_Interface ++ .comm _MT_Interface,0,4 ++ .data ++ .align 4 ++ .type _catch_classes_Interface, @object ++ .size _catch_classes_Interface, 24 ++_catch_classes_Interface: ++ .zero 24 ++ .section .rodata ++ .align 2 ++ .type _Utf1, @object ++ .size _Utf1, 4 ++_Utf1: ++ .value 36121 ++ .value 9 ++ .ascii "Interface" ++ .zero 1 ++.globl _ZN9Interface6class$E ++ .data ++ .align 32 ++ .type _ZN9Interface6class$E, @object ++ .size _ZN9Interface6class$E, 144 ++_ZN9Interface6class$E: ++ .long _ZTVN4java4lang5ClassE+8 ++ .long 403000 ++ .long _Utf1 ++ .value 1536 ++ .zero 2 ++ .long 0 ++ .long 0 ++ .long 0 ++ .long 0 ++ .long _MT_Interface ++ .value 0 ++ .value 6 ++ .long 0 ++ .long 4 ++ .value 0 ++ .value 0 ++ .long 0 ++ .long 0 ++ .long 0 ++ .long 0 ++ .long 0 ++ .long 0 ++ .long 0 ++ .long _catch_classes_Interface ++ .long 0 ++ .long 0 ++ .value 0 ++ .byte 1 ++ .zero 1 ++ .long 0 ++ .value 0 ++ .zero 2 ++ .long 0 ++ .long 0 ++ .long 0 ++ .long 0 ++ .long 0 ++ .long 0 ++ .long 0 ++ .long 0 ++ .long 0 ++ .long 0 ++ .hidden _ZN9Interface7class$$E ++.globl _ZN9Interface7class$$E ++ .section .rodata ++ .align 4 ++ .type _ZN9Interface7class$$E, @object ++ .size _ZN9Interface7class$$E, 4 ++_ZN9Interface7class$$E: ++ .long _ZN9Interface6class$E ++ .text ++ .align 2 ++.globl _ZN5ClassC1Ev ++ .type _ZN5ClassC1Ev, @function ++_ZN5ClassC1Ev: ++.LFB2: ++ pushl %ebp ++.LCFI0: ++ movl %esp, %ebp ++.LCFI1: ++ subl $24, %esp ++.LCFI2: ++.LBB2: ++#if 0 ++ .file 1 "interface.java" ++#else ++ .file "interface.java" ++#endif ++ .loc 1 4 0 ++ movl 8(%ebp), %eax ++ movl %eax, -4(%ebp) ++ movl -4(%ebp), %eax ++ movl %eax, (%esp) ++ call _ZN4java4lang6ObjectC1Ev ++.LBE2: ++ leave ++ ret ++.LFE2: ++ .size _ZN5ClassC1Ev, .-_ZN5ClassC1Ev ++ .hidden _ZTVN5ClassE ++.globl _ZTVN5ClassE ++ .data ++ .align 32 ++ .type _ZTVN5ClassE, @object ++ .size _ZTVN5ClassE, 40 ++_ZTVN5ClassE: ++ .long 0 ++ .long 0 ++ .long _ZN5Class6class$E ++ .long 4 ++ .long _ZN4java4lang6Object8finalizeEJvv ++ .long _ZN4java4lang6Object8hashCodeEJiv ++ .long _ZN4java4lang6Object6equalsEJbPS1_ ++ .long _ZN4java4lang6Object8toStringEJPNS0_6StringEv ++ .long _ZN4java4lang6Object5cloneEJPS1_v ++ .long _ZN4java4lang6Object22throwNoSuchMethodErrorEJvv ++ .set .L_ZN5ClassC1Ev0,_ZN5ClassC1Ev ++ .section .rodata ++ .align 2 ++ .type _Utf2, @object ++ .size _Utf2, 4 ++_Utf2: ++ .value 626 ++ .value 6 ++ .ascii "" ++ .zero 1 ++ .align 2 ++ .type _Utf3, @object ++ .size _Utf3, 4 ++_Utf3: ++ .value 39797 ++ .value 3 ++ .ascii "()V" ++ .zero 1 ++ .data ++ .align 4 ++ .type _MT_Class, @object ++ .size _MT_Class, 20 ++_MT_Class: ++ .long _Utf2 ++ .long _Utf3 ++ .value 16384 ++ .value -1 ++ .long .L_ZN5ClassC1Ev0 ++ .long 0 ++ .align 4 ++ .type _IF_Class, @object ++ .size _IF_Class, 4 ++_IF_Class: ++ .long _ZN9Interface6class$E ++ .align 4 ++ .type _catch_classes_Class, @object ++ .size _catch_classes_Class, 24 ++_catch_classes_Class: ++ .zero 24 ++ .section .rodata ++ .align 2 ++ .type _Utf4, @object ++ .size _Utf4, 4 ++_Utf4: ++ .value 47448 ++ .value 5 ++ .ascii "Class" ++ .zero 1 ++.globl _ZN5Class6class$E ++ .data ++ .align 32 ++ .type _ZN5Class6class$E, @object ++ .size _ZN5Class6class$E, 144 ++_ZN5Class6class$E: ++ .long _ZTVN4java4lang5ClassE+8 ++ .long 403000 ++ .long _Utf4 ++ .value 32 ++ .zero 2 ++ .long _ZN4java4lang6Object6class$E ++ .long 0 ++ .long 0 ++ .long 0 ++ .long _MT_Class ++ .value 1 ++ .value 6 ++ .long 0 ++ .long 4 ++ .value 0 ++ .value 0 ++ .long _ZTVN5ClassE+8 ++ .long 0 ++ .long 0 ++ .long 0 ++ .long 0 ++ .long 0 ++ .long 0 ++ .long _catch_classes_Class ++ .long _IF_Class ++ .long 0 ++ .value 1 ++ .byte 1 ++ .zero 1 ++ .long 0 ++ .value 0 ++ .zero 2 ++ .long 0 ++ .long 0 ++ .long 0 ++ .long 0 ++ .long 0 ++ .long 0 ++ .long 0 ++ .long 0 ++ .long 0 ++ .long 0 ++ .hidden _ZN5Class7class$$E ++.globl _ZN5Class7class$$E ++ .section .rodata ++ .align 4 ++ .type _ZN5Class7class$$E, @object ++ .size _ZN5Class7class$$E, 4 ++_ZN5Class7class$$E: ++ .long _ZN5Class6class$E ++ .section .jcr,"aw",@progbits ++ .align 4 ++ .long _ZN9Interface6class$E ++ .long _ZN5Class6class$E ++ .section .debug_frame,"",@progbits ++.Lframe0: ++ .long .LECIE0-.LSCIE0 ++.LSCIE0: ++ .long 0xffffffff ++ .byte 0x1 ++ .string "" ++ .uleb128 0x1 ++ .sleb128 -4 ++ .byte 0x8 ++ .byte 0xc ++ .uleb128 0x4 ++ .uleb128 0x4 ++ .byte 0x88 ++ .uleb128 0x1 ++ .align 4 ++.LECIE0: ++.LSFDE0: ++ .long .LEFDE0-.LASFDE0 ++.LASFDE0: ++ .long .Lframe0 ++ .long .LFB2 ++ .long .LFE2-.LFB2 ++ .byte 0x4 ++ .long .LCFI0-.LFB2 ++ .byte 0xe ++ .uleb128 0x8 ++ .byte 0x85 ++ .uleb128 0x2 ++ .byte 0x4 ++ .long .LCFI1-.LCFI0 ++ .byte 0xd ++ .uleb128 0x5 ++ .align 4 ++.LEFDE0: ++ .section .eh_frame,"a",@progbits ++.Lframe1: ++ .long .LECIE1-.LSCIE1 ++.LSCIE1: ++ .long 0x0 ++ .byte 0x1 ++.globl __gcj_personality_v0 ++ .string "zP" ++ .uleb128 0x1 ++ .sleb128 -4 ++ .byte 0x8 ++ .uleb128 0x5 ++ .byte 0x0 ++ .long __gcj_personality_v0 ++ .byte 0xc ++ .uleb128 0x4 ++ .uleb128 0x4 ++ .byte 0x88 ++ .uleb128 0x1 ++ .align 4 ++.LECIE1: ++.LSFDE1: ++ .long .LEFDE1-.LASFDE1 ++.LASFDE1: ++ .long .LASFDE1-.Lframe1 ++ .long .LFB2 ++ .long .LFE2-.LFB2 ++ .uleb128 0x0 ++ .byte 0x4 ++ .long .LCFI0-.LFB2 ++ .byte 0xe ++ .uleb128 0x8 ++ .byte 0x85 ++ .uleb128 0x2 ++ .byte 0x4 ++ .long .LCFI1-.LCFI0 ++ .byte 0xd ++ .uleb128 0x5 ++ .align 4 ++.LEFDE1: ++ .text ++.Letext0: ++ .section .debug_loc,"",@progbits ++.Ldebug_loc0: ++.LLST0: ++ .long .LFB2-.Ltext0 ++ .long .LCFI0-.Ltext0 ++ .value 0x2 ++ .byte 0x74 ++ .sleb128 4 ++ .long .LCFI0-.Ltext0 ++ .long .LCFI1-.Ltext0 ++ .value 0x2 ++ .byte 0x74 ++ .sleb128 8 ++ .long .LCFI1-.Ltext0 ++ .long .LFE2-.Ltext0 ++ .value 0x2 ++ .byte 0x75 ++ .sleb128 8 ++ .long 0x0 ++ .long 0x0 ++ .section .debug_info ++ .long 0x117 ++ .value 0x2 ++ .long .Ldebug_abbrev0 ++ .byte 0x4 ++ .uleb128 0x1 ++ .string "GNU Java 4.3.0 20071221 (experimental)" ++ .byte 0xb ++ .string "interface.java" ++ .string "/home/jkratoch/redhat/bz371831" ++ .long .Ltext0 ++ .long .Letext0 ++ .long .Ldebug_line0 ++ .uleb128 0x2 ++ .string "Interface" ++ .byte 0x4 ++ .byte 0x1 ++ .byte 0x0 ++ .long 0x8e ++ .long 0x8e ++ .uleb128 0x3 ++ .long 0x8e ++ .byte 0x2 ++ .byte 0x23 ++ .uleb128 0x0 ++ .byte 0x1 ++ .byte 0x0 ++ .uleb128 0x4 ++ .string "java.lang.Object" ++ .byte 0x1 ++ .uleb128 0x5 ++ .string "Class" ++ .byte 0x4 ++ .byte 0x1 ++ .byte 0x0 ++ .long 0x8e ++ .long 0xe8 ++ .uleb128 0x3 ++ .long 0x8e ++ .byte 0x2 ++ .byte 0x23 ++ .uleb128 0x0 ++ .byte 0x1 ++ .uleb128 0x6 ++ .long 0x6e ++ .byte 0x2 ++ .byte 0x23 ++ .uleb128 0x0 ++ .byte 0x1 ++ .byte 0x1 ++ .uleb128 0x7 ++ .byte 0x1 ++ .string "" ++ .byte 0x1 ++ .byte 0x0 ++ .string "_ZN5ClassC1Ev" ++ .byte 0x1 ++ .uleb128 0x8 ++ .long 0xe8 ++ .byte 0x1 ++ .byte 0x0 ++ .byte 0x0 ++ .uleb128 0x9 ++ .byte 0x4 ++ .long 0xa1 ++ .uleb128 0xa ++ .long 0xc6 ++ .long .LFB2 ++ .long .LFE2 ++ .long .LLST0 ++ .long 0x114 ++ .uleb128 0xb ++ .long 0xe8 ++ .byte 0x2 ++ .byte 0x91 ++ .sleb128 0 ++ .uleb128 0xc ++ .long 0x114 ++ .byte 0x2 ++ .byte 0x91 ++ .sleb128 -12 ++ .byte 0x0 ++ .uleb128 0x9 ++ .byte 0x4 ++ .long 0x8e ++ .byte 0x0 ++ .section .debug_abbrev ++ .uleb128 0x1 ++ .uleb128 0x11 ++ .byte 0x1 ++ .uleb128 0x25 ++ .uleb128 0x8 ++ .uleb128 0x13 ++ .uleb128 0xb ++ .uleb128 0x3 ++ .uleb128 0x8 ++ .uleb128 0x1b ++ .uleb128 0x8 ++ .uleb128 0x11 ++ .uleb128 0x1 ++ .uleb128 0x12 ++ .uleb128 0x1 ++ .uleb128 0x10 ++ .uleb128 0x6 ++ .byte 0x0 ++ .byte 0x0 ++ .uleb128 0x2 ++ .uleb128 0x38 ++ .byte 0x1 ++ .uleb128 0x3 ++ .uleb128 0x8 ++ .uleb128 0xb ++ .uleb128 0xb ++ .uleb128 0x3a ++ .uleb128 0xb ++ .uleb128 0x3b ++ .uleb128 0xb ++ .uleb128 0x1d ++ .uleb128 0x13 ++ .uleb128 0x1 ++ .uleb128 0x13 ++ .byte 0x0 ++ .byte 0x0 ++ .uleb128 0x3 ++ .uleb128 0x1c ++ .byte 0x0 ++ .uleb128 0x49 ++ .uleb128 0x13 ++ .uleb128 0x38 ++ .uleb128 0xa ++ .uleb128 0x32 ++ .uleb128 0xb ++ .byte 0x0 ++ .byte 0x0 ++ .uleb128 0x4 ++ .uleb128 0x2 ++ .byte 0x0 ++ .uleb128 0x3 ++ .uleb128 0x8 ++ .uleb128 0x3c ++ .uleb128 0xc ++ .byte 0x0 ++ .byte 0x0 ++ .uleb128 0x5 ++ .uleb128 0x2 ++ .byte 0x1 ++ .uleb128 0x3 ++ .uleb128 0x8 ++ .uleb128 0xb ++ .uleb128 0xb ++ .uleb128 0x3a ++ .uleb128 0xb ++ .uleb128 0x3b ++ .uleb128 0xb ++ .uleb128 0x1d ++ .uleb128 0x13 ++ .uleb128 0x1 ++ .uleb128 0x13 ++ .byte 0x0 ++ .byte 0x0 ++ .uleb128 0x6 ++ .uleb128 0x1c ++ .byte 0x0 ++ .uleb128 0x49 ++ .uleb128 0x13 ++ .uleb128 0x38 ++ .uleb128 0xa ++ .uleb128 0x4c ++ .uleb128 0xb ++ .uleb128 0x32 ++ .uleb128 0xb ++ .byte 0x0 ++ .byte 0x0 ++ .uleb128 0x7 ++ .uleb128 0x2e ++ .byte 0x1 ++ .uleb128 0x3f ++ .uleb128 0xc ++ .uleb128 0x3 ++ .uleb128 0x8 ++ .uleb128 0x3a ++ .uleb128 0xb ++ .uleb128 0x3b ++ .uleb128 0xb ++ .uleb128 0x2007 ++ .uleb128 0x8 ++ .uleb128 0x3c ++ .uleb128 0xc ++ .byte 0x0 ++ .byte 0x0 ++ .uleb128 0x8 ++ .uleb128 0x5 ++ .byte 0x0 ++ .uleb128 0x49 ++ .uleb128 0x13 ++ .uleb128 0x34 ++ .uleb128 0xc ++ .byte 0x0 ++ .byte 0x0 ++ .uleb128 0x9 ++ .uleb128 0xf ++ .byte 0x0 ++ .uleb128 0xb ++ .uleb128 0xb ++ .uleb128 0x49 ++ .uleb128 0x13 ++ .byte 0x0 ++ .byte 0x0 ++ .uleb128 0xa ++ .uleb128 0x2e ++ .byte 0x1 ++ .uleb128 0x47 ++ .uleb128 0x13 ++ .uleb128 0x11 ++ .uleb128 0x1 ++ .uleb128 0x12 ++ .uleb128 0x1 ++ .uleb128 0x40 ++ .uleb128 0x6 ++ .uleb128 0x1 ++ .uleb128 0x13 ++ .byte 0x0 ++ .byte 0x0 ++ .uleb128 0xb ++ .uleb128 0x5 ++ .byte 0x0 ++ .uleb128 0x49 ++ .uleb128 0x13 ++ .uleb128 0x2 ++ .uleb128 0xa ++ .byte 0x0 ++ .byte 0x0 ++ .uleb128 0xc ++ .uleb128 0x34 ++ .byte 0x0 ++ .uleb128 0x49 ++ .uleb128 0x13 ++ .uleb128 0x2 ++ .uleb128 0xa ++ .byte 0x0 ++ .byte 0x0 ++ .byte 0x0 ++ .section .debug_pubnames,"",@progbits ++ .long 0x15 ++ .value 0x2 ++ .long .Ldebug_info0 ++ .long 0x11b ++ .long 0xee ++ .string "()" ++ .long 0x0 ++ .section .debug_aranges,"",@progbits ++ .long 0x1c ++ .value 0x2 ++ .long .Ldebug_info0 ++ .byte 0x4 ++ .byte 0x0 ++ .value 0x0 ++ .value 0x0 ++ .long .Ltext0 ++ .long .Letext0-.Ltext0 ++ .long 0x0 ++ .long 0x0 ++ .ident "GCC: (GNU) 4.3.0 20071221 (experimental)" ++ .section .note.GNU-stack,"",@progbits +--- /dev/null 1 Jan 1970 00:00:00 -0000 ++++ ./gdb/testsuite/gdb.arch/i386-interface.exp 22 Dec 2007 19:07:28 -0000 +@@ -0,0 +1,66 @@ ++# Copyright 2007 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++# Please email any bugs, comments, and/or additions to this file to: ++# bug-gdb@gnu.org ++ ++# This file is part of the gdb testsuite. ++ ++# Test basis recognization of DW_TAG_interface_type. ++# GCC java_classify_record() produces it if returns RECORD_IS_INTERFACE. ++ ++if $tracelevel { ++ strace $tracelevel ++} ++ ++set prms_id 0 ++set bug_id 0 ++ ++if {![istarget "i?86-*-*"] && ![istarget "x86_64-*-*"]} then { ++ verbose "Skipping i386 Java DW_TAG_interface_type test." ++ return ++} ++ ++set testfile "i386-interface" ++set srcfile ${testfile}.S ++set binfile ${objdir}/${subdir}/${testfile}.o ++ ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" object {debug additional_flags=-m32}] != "" } { ++ untested i386-gnu-cfi.exp ++ return -1 ++} ++ ++# Get things started. ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++gdb_test "set language java" ++ ++set test "ptype Interface" ++gdb_test_multiple $test $test { ++ -re "type = class Interface *extends java.lang.Object \{.*$gdb_prompt $" { ++ pass $test ++ } ++} ++ ++set test "ptype Class" ++gdb_test_multiple $test $test { ++ -re "type = class Class *extends java.lang.Object implements Interface \{.*$gdb_prompt $" { ++ pass $test ++ } ++} diff --git a/gdb-6.7-charsign-test.patch b/gdb-6.7-charsign-test.patch new file mode 100644 index 0000000..2e289ac --- /dev/null +++ b/gdb-6.7-charsign-test.patch @@ -0,0 +1,125 @@ +https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=224128 + +2007-01-25 Jan Kratochvil + + * gdb.base/charsign.exp, gdb.base/charsign.c: New files. + [ stripped ] + +2007-10-19 Jan Kratochvil + + Port to GDB-6.7 - only the testcase left, patch has been reverted, + char-vectors restricted. + +--- /dev/null 1 Jan 1970 00:00:00 -0000 ++++ ./gdb/testsuite/gdb.base/charsign.c 26 Jan 2007 10:32:00 -0000 +@@ -0,0 +1,37 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2007 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++ Please email any bugs, comments, and/or additions to this file to: ++ bug-gdb@prep.ai.mit.edu */ ++ ++int main() ++{ ++ return 0; ++} ++ ++char n[]="A"; ++signed char s[]="A"; ++unsigned char u[]="A"; ++ ++typedef char char_n; ++typedef signed char char_s; ++typedef unsigned char char_u; ++ ++char_n n_typed[]="A"; ++char_s s_typed[]="A"; ++char_u u_typed[]="A"; +--- /dev/null 1 Jan 1970 00:00:00 -0000 ++++ ./gdb/testsuite/gdb.base/charsign.exp 26 Jan 2007 10:32:00 -0000 +@@ -0,0 +1,70 @@ ++# Copyright 2007 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++if $tracelevel then { ++ strace $tracelevel ++} ++ ++set prms_id 0 ++set bug_id 0 ++ ++set testfile charsign ++set srcfile ${testfile}.c ++set binfile ${objdir}/${subdir}/${testfile} ++ ++proc do_test { cflags } { ++ global srcdir ++ global binfile ++ global subdir ++ global srcfile ++ global gdb_prompt ++ ++ if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable [list debug additional_flags=$cflags]] != "" } { ++ untested "Couldn't compile test program" ++ return -1 ++ } ++ ++ # Get things started. ++ ++ gdb_exit ++ gdb_start ++ gdb_reinitialize_dir $srcdir/$subdir ++ gdb_load ${binfile} ++ ++ # For C programs, "start" should stop in main(). ++ ++ gdb_test "p n" \ ++ "= \"A\"" ++ gdb_test "p s" \ ++ "= \\{65 'A', 0 '\\\\0'\\}" ++ gdb_test "p u" \ ++ "= \\{65 'A', 0 '\\\\0'\\}" ++ gdb_test "p n_typed" \ ++ "= \"A\"" ++ gdb_test "p s_typed" \ ++ "= \\{65 'A', 0 '\\\\0'\\}" ++ gdb_test "p u_typed" \ ++ "= \\{65 'A', 0 '\\\\0'\\}" ++} ++ ++# The string identification works despite the compiler flags below due to ++# gdbtypes.c: ++# if (name && strcmp (name, "char") == 0) ++# TYPE_FLAGS (type) |= TYPE_FLAG_NOSIGN; ++ ++do_test {} ++do_test {-fsigned-char} ++do_test {-funsigned-char} diff --git a/gdb-6.7-kernel-headers-compat.patch b/gdb-6.7-kernel-headers-compat.patch new file mode 100644 index 0000000..f169b78 --- /dev/null +++ b/gdb-6.7-kernel-headers-compat.patch @@ -0,0 +1,24 @@ +kernel-headers-2.6.25-0.40.rc1.git2.fc9.x86_64 + +In file included from /usr/include/asm/ptrace.h:4, + from ../../gdb/amd64-linux-nat.c:44: +/usr/include/asm/ptrace-abi.h:92: error: expected specifier-qualifier-list before ‘u32’ + +--- gdb-6.7.1-13.fc9.x86_64/gdb/amd64-linux-nat.c-orig 2008-02-15 15:37:28.000000000 -0500 ++++ gdb-6.7.1-13.fc9.x86_64/gdb/amd64-linux-nat.c 2008-02-15 15:40:13.000000000 -0500 +@@ -35,13 +35,13 @@ + #include + #include + /* FIXME ezannoni-2003-07-09: we need to be included after +- because the latter redefines FS and GS for no apparent ++ because the latter redefines FS and GS for no apparent + reason, and those definitions don't match the ones that libpthread_db + uses, which come from . */ + /* ezannoni-2003-07-09: I think this is fixed. The extraneous defs have + been removed from ptrace.h in the kernel. However, better safe than + sorry. */ +-#include ++#include + #include + #include "gdb_proc_service.h" + diff --git a/gdb-6.7-ppc-clobbered-registers-O2-test.patch b/gdb-6.7-ppc-clobbered-registers-O2-test.patch new file mode 100644 index 0000000..b8ba5b0 --- /dev/null +++ b/gdb-6.7-ppc-clobbered-registers-O2-test.patch @@ -0,0 +1,103 @@ +2007-11-04 Jan Kratochvil + + * gdb.arch/ppc-clobbered-registers-O2.exp: `powerpc64' changed to + `powerpc*'. + +Testcase for: + +http://sourceware.org/ml/gdb-patches/2007-09/msg00228.html + +2007-10-21 Luis Machado + + * rs6000-tdep.c (ppc_dwarf2_frame_init_reg): New function. + * (rs6000_gdbarch_init): Install ppc_dwarf2_frame_init_reg as + default dwarf2_frame_set_init_reg function. + +--- /dev/null 1 Jan 1970 00:00:00 -0000 ++++ ./gdb/testsuite/gdb.arch/ppc-clobbered-registers-O2.c 3 Nov 2007 22:22:28 -0000 +@@ -0,0 +1,21 @@ ++ ++unsigned * __attribute__((noinline)) ++start_sequence (unsigned * x, unsigned * y) ++{ ++ return (unsigned *)0xdeadbeef; ++}; ++ ++unsigned __attribute__((noinline)) ++gen_movsd (unsigned * operand0, unsigned * operand1) ++{ ++ return *start_sequence(operand0, operand1); ++} ++ ++int main(void) ++{ ++ unsigned x, y; ++ ++ x = 13; ++ y = 14; ++ return (int)gen_movsd (&x, &y); ++} +--- /dev/null 1 Jan 1970 00:00:00 -0000 ++++ ./gdb/testsuite/gdb.arch/ppc-clobbered-registers-O2.exp 3 Nov 2007 22:22:28 -0000 +@@ -0,0 +1,61 @@ ++# Copyright 2006 Free Software Foundation, Inc. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++# ++# This file is part of the gdb testsuite. ++ ++if $tracelevel { ++ strace $tracelevel ++} ++ ++# Test displaying call clobbered registers in optimized binaries for ppc. ++# GDB should not show incorrect values. ++ ++set prms_id 0 ++set bug_id 0 ++ ++if ![istarget "powerpc*-*"] then { ++ verbose "Skipping powerpc* call clobbered registers testing." ++ return ++} ++ ++set testfile "ppc-clobbered-registers-O2" ++set srcfile ${testfile}.c ++set binfile ${objdir}/${subdir}/${testfile} ++set compile_flags "debug additional_flags=-O2" ++ ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable ${compile_flags}] != "" } { ++ unsupported "Testcase compile failed." ++ return -1 ++} ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++if ![runto_main] then { ++ perror "Couldn't run to breakpoint" ++ continue ++} ++ ++gdb_test "b start_sequence" ".*Breakpoint 2 at.*line 6.*" \ ++ "Insert breakpoint at problematic function" ++ ++gdb_test continue ".*Breakpoint 2.*in start_sequence.*" \ ++ "Run until problematic function" ++ ++gdb_test backtrace ".*operand0=.*operand1=.*" \ ++ "Check value of call clobbered registers" diff --git a/gdb-6.7-testsuite-stable-results.patch b/gdb-6.7-testsuite-stable-results.patch new file mode 100644 index 0000000..50273e4 --- /dev/null +++ b/gdb-6.7-testsuite-stable-results.patch @@ -0,0 +1,208 @@ +gdb/testsuite/gdb.base/fileio.c: +gdb/testsuite/gdb.base/fileio.exp: +2007-12-08 Jan Kratochvil + + * gdb.base/fileio.c (ROOTSUBDIR): New macro. + (main): CHDIR into ROOTSUBDIR. CHOWN ROOTSUBDIR and CHDIR into + ROOTSUBDIR if we are being run as root. + * gdb.base/fileio.exp: Change the startup and finish cleanup. + Change the test file reference to be into the `fileio.dir' directory. + + +sources/gdb/testsuite/gdb.base/dump.exp: +Found on RHEL-5.s390x. + + +gdb-6.8.50.20090209/gdb/testsuite/gdb.base/auxv.exp: +random FAIL: gdb.base/auxv.exp: matching auxv data from live and gcore + + +gdb-6.8.50.20090209/gdb/testsuite/gdb.base/annota1.exp: +frames-invalid can happen asynchronously. + +--- ./gdb/testsuite/gdb.base/fileio.c 13 Jun 2006 08:55:22 -0000 1.10 ++++ ./gdb/testsuite/gdb.base/fileio.c 8 Dec 2007 16:04:10 -0000 +@@ -58,6 +58,8 @@ system (const char * string); + 1) Invalid string/command. - returns 127. */ + static const char *strerrno (int err); + ++#define ROOTSUBDIR "fileio.dir" ++ + #define FILENAME "foo.fileio.test" + #define RENAMED "bar.fileio.test" + #define NONEXISTANT "nofoo.fileio.test" +@@ -542,6 +544,37 @@ strerrno (int err) + int + main () + { ++ /* ROOTSUBDIR is already prepared by fileio.exp. We use it for easy cleanup ++ (by fileio.exp) if we are run by multiple users in the same directory. */ ++ ++ if (chdir (ROOTSUBDIR) != 0) ++ { ++ printf ("chdir " ROOTSUBDIR ": %s\n", strerror (errno)); ++ exit (1); ++ } ++ ++ /* These tests ++ Open for write but no write permission returns EACCES ++ Unlinking a file in a directory w/o write access returns EACCES ++ fail if we are being run as root - drop the privileges here. */ ++ ++ if (geteuid () == 0) ++ { ++ uid_t uid = 99; ++ ++ if (chown (".", uid, uid) != 0) ++ { ++ printf ("chown %d.%d " ROOTSUBDIR ": %s\n", (int) uid, (int) uid, ++ strerror (errno)); ++ exit (1); ++ } ++ if (setuid (uid) || geteuid () == 0) ++ { ++ printf ("setuid %d: %s\n", (int) uid, strerror (errno)); ++ exit (1); ++ } ++ } ++ + /* Don't change the order of the calls. They partly depend on each other */ + test_open (); + test_write (); +--- ./gdb/testsuite/gdb.base/fileio.exp 23 Aug 2007 18:14:16 -0000 1.12 ++++ ./gdb/testsuite/gdb.base/fileio.exp 8 Dec 2007 16:04:10 -0000 +@@ -46,8 +46,8 @@ if [get_compiler_info ${binfile}] { + return -1; + } + +-remote_exec build {sh -xc test\ -r\ dir2.fileio.test\ &&\ chmod\ -f\ +w\ dir2.fileio.test} +-remote_exec build {sh -xc rm\ -rf\ *.fileio.test} ++remote_exec build {sh -xc rm\ -rf\ fileio.dir} ++remote_exec build {sh -xc mkdir\ -m777\ fileio.dir} + + set oldtimeout $timeout + set timeout [expr "$timeout + 60"] +@@ -88,7 +88,7 @@ gdb_test continue \ + "Opening nonexistant file returns ENOENT" + + send_gdb "continue\n" ; gdb_expect -re "$gdb_prompt $" +-catch "system \"chmod -f -w nowrt.fileio.test\"" ++catch "system \"chmod -f -w fileio.dir/nowrt.fileio.test\"" + + gdb_test continue \ + "Continuing\\..*open 5:.*EACCES$stop_msg" \ +@@ -252,8 +252,8 @@ gdb_test continue \ + send_gdb "quit\n" + send_gdb "y\n" + +-remote_exec build {sh -xc test\ -r\ dir2.fileio.test\ &&\ chmod\ -f\ +w\ dir2.fileio.test} +-remote_exec build {sh -xc rm\ -rf\ *.fileio.test} ++remote_exec build {sh -xc test\ -r\ fileio.dir/dir2.fileio.test\ &&\ chmod\ -f\ +w\ fileio.dir/dir2.fileio.test} ++remote_exec build {sh -xc rm\ -rf\ fileio.dir} + + set timeout $oldtimeout + return 0 +--- sources/gdb/testsuite/gdb.base/dump.exp-orig 2008-08-28 11:44:40.000000000 +0200 ++++ sources/gdb/testsuite/gdb.base/dump.exp 2008-08-28 11:44:49.000000000 +0200 +@@ -493,8 +493,10 @@ if ![string compare $is64bitonly "no"] t + gdb_test "print zero_all ()" "" "" + + # restore with expressions ++ # Address may fit in int32 but its negative result would be 0xffffxxxx for ++ # 64-bit LONGEST addresses. + test_restore_saved_value \ +- "intarr3.srec ${array2_start}-${array_start} &intarray\[3\] &intarray\[4\]" \ ++ "intarr3.srec (long)${array2_start}-${array_start} &intarray\[3\] &intarray\[4\]" \ + "array partial with expressions" 4 "intarray2\[3\]" + + gdb_test "print intarray2\[2\] == 0" " = 1" "element 2 not changed, == 4" +--- gdb-6.8.50.20090209/gdb/testsuite/gdb.base/annota1.exp-orig 2009-02-09 16:31:11.000000000 +0100 ++++ gdb-6.8.50.20090209/gdb/testsuite/gdb.base/annota1.exp 2009-02-09 21:27:38.000000000 +0100 +@@ -286,7 +286,7 @@ if [target_info exists gdb,nosignals] { + } else { + send_gdb "signal SIGUSR1\n" + gdb_expect { +- -re "\r\n\032\032post-prompt\r\nContinuing with signal SIGUSR1.\r\n\r\n\032\032starting\r\n\r\n\032\032frames-invalid\r\n\r\n\032\032breakpoint 2\r\n\r\nBreakpoint 2, \r\n\032\032frame-begin 0 $hex\r\n\r\n\032\032frame-function-name\r\nhandle_USR1\r\n\032\032frame-args\r\n \\(\r\n\032\032arg-begin\r\nsig\r\n\032\032arg-name-end\r\n=\r\n\032\032arg-value -\r\n$decimal\r\n\032\032arg-end\r\n\\)\r\n\032\032frame-source-begin\r\n at \r\n\032\032frame-source-file\r\n${escapedsrcfile}\r\n\032\032frame-source-file-end\r\n:\r\n\032\032frame-source-line\r\n.*\r\n\032\032frame-source-end\r\n\r\n\r\n\032\032source.*annota1.c:.*:.*:beg:$hex\r\n\r\n\032\032frame-end\r\n\r\n\032\032stopped\r\n$gdb_prompt$" \ ++ -re "\r\n\032\032post-prompt\r\nContinuing with signal SIGUSR1.\r\n\r\n\032\032starting\r\n(\r\n\032\032frames-invalid\r\n)*\r\n\032\032breakpoint 2\r\n\r\nBreakpoint 2, \r\n\032\032frame-begin 0 $hex\r\n\r\n\032\032frame-function-name\r\nhandle_USR1\r\n\032\032frame-args\r\n \\(\r\n\032\032arg-begin\r\nsig\r\n\032\032arg-name-end\r\n=\r\n\032\032arg-value -\r\n$decimal\r\n\032\032arg-end\r\n\\)\r\n\032\032frame-source-begin\r\n at \r\n\032\032frame-source-file\r\n${escapedsrcfile}\r\n\032\032frame-source-file-end\r\n:\r\n\032\032frame-source-line\r\n.*\r\n\032\032frame-source-end\r\n\r\n\r\n\032\032source.*annota1.c:.*:.*:beg:$hex\r\n\r\n\032\032frame-end\r\n\r\n\032\032stopped\r\n$gdb_prompt$" \ + { pass "send SIGUSR1" } + -re "\r\n\032\032post-prompt\r\nContinuing with signal SIGUSR1.\r\n\r\n\032\032starting\r\n\r\n\032\032frames-invalid\r\n\r\n\032\032breakpoint 2\r\n\r\nBreakpoint 2, \r\n\032\032frame-begin 0 $hex\r\n\r\n\032\032frame-function-name\r\nhandle_USR1\r\n\032\032frame-args\r\n \\(\r\n\032\032arg-begin\r\nsig\r\n\032\032arg-name-end\r\n=\r\n\032\032arg-value -\r\n$decimal\r\n\032\032arg-end\r\n\\)\r\n\032\032frame-source-begin\r\n at \r\n\032\032frame-source-file\r\n.*${srcfile}\r\n\032\032frame-source-file-end\r\n:\r\n\032\032frame-source-line\r\n.*\r\n\032\032frame-source-end\r\n\r\n\r\n\032\032source.*annota1.c:.*:.*:beg:$hex\r\n\r\n\032\032frame-end\r\n\r\n\032\032stopped\r\n$gdb_prompt$" \ + { setup_xfail "*-*-*" 1270 +--- ./gdb/testsuite/gdb.base/auxv.exp 2009-02-11 00:54:54.000000000 +0100 ++++ ./gdb/testsuite/gdb.base/auxv.exp 2009-02-11 00:51:30.000000000 +0100 +@@ -78,8 +78,10 @@ proc fetch_auxv {test} { + + set auxv_lines {} + set bad -1 ++ # Former trailing `\[\r\n\]+' may eat just \r leaving \n in the buffer ++ # corrupting the next matches. + if {[gdb_test_multiple "info auxv" $test { +- -re "info auxv\[\r\n\]+" { ++ -re "info auxv\r\n" { + exp_continue + } + -ex "The program has no auxiliary information now" { +@@ -94,20 +96,20 @@ proc fetch_auxv {test} { + set bad 1 + exp_continue + } +- -re "^\[0-9\]+\[ \t\]+(AT_\[^ \t\]+)\[^\r\n\]+\[\r\n\]+" { ++ -re "^\[0-9\]+\[ \t\]+(AT_\[^ \t\]+)\[^\r\n\]+\r\n" { + lappend auxv_lines $expect_out(0,string) + exp_continue + } +- -re "^\[0-9\]+\[ \t\]+\\?\\?\\?\[^\r\n\]+\[\r\n\]+" { ++ -re "^\[0-9\]+\[ \t\]+\\?\\?\\?\[^\r\n\]+\r\n" { + warning "Unrecognized tag value: $expect_out(0,string)" + set bad 1 + lappend auxv_lines $expect_out(0,string) + exp_continue + } +- -re ".*$gdb_prompt $" { ++ -re "$gdb_prompt $" { + incr bad + } +- -re "^\[^\r\n\]+\[\r\n\]+" { ++ -re "^\[^\r\n\]+\r\n" { + if {!$bad} { + warning "Unrecognized output: $expect_out(0,string)" + set bad 1 +--- ./gdb/testsuite/gdb.base/callfuncs.exp 2009-01-03 06:58:03.000000000 +0100 ++++ ./gdb/testsuite/gdb.base/callfuncs.exp 2009-02-11 00:51:42.000000000 +0100 +@@ -249,15 +249,17 @@ proc fetch_all_registers {test} { + + set all_registers_lines {} + set bad -1 ++ # Former trailing `\[\r\n\]+' may eat just \r leaving \n in the buffer ++ # corrupting the next matches. + if {[gdb_test_multiple "info all-registers" $test { +- -re "info all-registers\[\r\n\]+" { ++ -re "info all-registers\r\n" { + exp_continue + } + -ex "The program has no registers now" { + set bad 1 + exp_continue + } +- -re "^bspstore\[ \t\]+\[^\r\n\]+\[\r\n\]+" { ++ -re "^bspstore\[ \t\]+\[^\r\n\]+\r\n" { + if [istarget "ia64-*-*"] { + # Filter out bspstore which is specially tied to bsp, + # giving spurious differences. +@@ -266,14 +268,14 @@ proc fetch_all_registers {test} { + } + exp_continue + } +- -re "^\[^ \t\]+\[ \t\]+\[^\r\n\]+\[\r\n\]+" { ++ -re "^\[^ \t\]+\[ \t\]+\[^\r\n\]+\r\n" { + lappend all_registers_lines $expect_out(0,string) + exp_continue + } +- -re ".*$gdb_prompt $" { ++ -re "$gdb_prompt $" { + incr bad + } +- -re "^\[^\r\n\]+\[\r\n\]+" { ++ -re "^\[^\r\n\]+\r\n" { + if {!$bad} { + warning "Unrecognized output: $expect_out(0,string)" + set bad 1 diff --git a/gdb-6.8-attach-signalled-detach-stopped.patch b/gdb-6.8-attach-signalled-detach-stopped.patch new file mode 100644 index 0000000..a297ec4 --- /dev/null +++ b/gdb-6.8-attach-signalled-detach-stopped.patch @@ -0,0 +1,183 @@ +Index: gdb-6.8.50.20090209/gdb/linux-nat.c +=================================================================== +--- gdb-6.8.50.20090209.orig/gdb/linux-nat.c 2009-02-09 16:12:23.000000000 +0100 ++++ gdb-6.8.50.20090209/gdb/linux-nat.c 2009-02-09 16:15:30.000000000 +0100 +@@ -204,6 +204,9 @@ blocked. */ + static struct target_ops *linux_ops; + static struct target_ops linux_ops_saved; + ++/* PID of the inferior stopped by SIGSTOP before attaching (or zero). */ ++static pid_t pid_was_stopped; ++ + /* The method to call, if any, when a new thread is attached. */ + static void (*linux_nat_new_thread) (ptid_t); + +@@ -902,7 +905,14 @@ linux_child_follow_fork (struct target_o + fork_save_infrun_state (fp, 0); + } + else +- target_detach (NULL, 0); ++ { ++ /* We should check PID_WAS_STOPPED and detach it stopped accordingly. ++ In this point of code it cannot be 1 as we would not get FORK ++ executed without CONTINUE first which resets PID_WAS_STOPPED. ++ We would have to first TARGET_STOP and WAITPID it as with running ++ inferior PTRACE_DETACH, SIGSTOP will ignore the signal. */ ++ target_detach (NULL, 0); ++ } + + inferior_ptid = ptid_build (child_pid, child_pid, 0); + +@@ -1229,6 +1239,7 @@ linux_nat_post_attach_wait (ptid_t ptid, + if (debug_linux_nat) + fprintf_unfiltered (gdb_stdlog, + "LNPAW: Attaching to a stopped process\n"); ++ pid_was_stopped = GET_PID (ptid); + + /* The process is definitely stopped. It is in a job control + stop, unless the kernel predates the TASK_STOPPED / +@@ -1561,6 +1572,9 @@ GPT: lwp %s had signal %s, but it is in + *status = lp->status; + } + ++ if (*status == 0 && GET_PID (lp->ptid) == pid_was_stopped) ++ *status = W_STOPCODE (SIGSTOP); ++ + return 0; + } + +@@ -1671,6 +1685,8 @@ linux_nat_detach (struct target_ops *ops + } + else + linux_ops->to_detach (ops, args, from_tty); ++ ++ pid_was_stopped = 0; + } + + /* Resume LP. */ +@@ -1825,6 +1841,14 @@ linux_nat_resume (ptid_t ptid, int step_ + resume_callback. */ + lp->stopped = 0; + ++ /* At this point, we are going to resume the inferior and if we ++ have attached to a stopped process, we no longer should leave ++ it as stopped if the user detaches. PTID variable has PID set to LWP ++ while we need to check the real PID here. */ ++ ++ if (!step && lp && pid_was_stopped == GET_PID (lp->ptid)) ++ pid_was_stopped = 0; ++ + if (resume_all) + iterate_over_lwps (resume_callback, NULL); + +@@ -3316,6 +3340,8 @@ linux_nat_mourn_inferior (struct target_ + there are other viable forks to debug. Delete the exiting + one and context-switch to the first available. */ + linux_fork_mourn_inferior (); ++ ++ pid_was_stopped = 0; + } + + /* Convert a native/host siginfo object, into/from the siginfo in the +Index: gdb-6.8.50.20090209/gdb/testsuite/gdb.threads/attach-stopped.exp +=================================================================== +--- gdb-6.8.50.20090209.orig/gdb/testsuite/gdb.threads/attach-stopped.exp 2009-01-03 06:58:07.000000000 +0100 ++++ gdb-6.8.50.20090209/gdb/testsuite/gdb.threads/attach-stopped.exp 2009-02-09 16:12:41.000000000 +0100 +@@ -62,7 +62,65 @@ proc corefunc { threadtype } { + gdb_reinitialize_dir $srcdir/$subdir + gdb_load ${binfile} + +- # Verify that we can attach to the stopped process. ++ # Verify that we can attach to the process by first giving its ++ # executable name via the file command, and using attach with the ++ # process ID. ++ ++ set test "$threadtype: set file, before attach1 to stopped process" ++ gdb_test_multiple "file $binfile" "$test" { ++ -re "Load new symbol table from.*y or n. $" { ++ gdb_test "y" "Reading symbols from $escapedbinfile\.\.\.*done." \ ++ "$test (re-read)" ++ } ++ -re "Reading symbols from $escapedbinfile\.\.\.*done.*$gdb_prompt $" { ++ pass "$test" ++ } ++ } ++ ++ set test "$threadtype: attach1 to stopped, after setting file" ++ gdb_test_multiple "attach $testpid" "$test" { ++ -re "Attaching to program.*`?$escapedbinfile'?, process $testpid.*$gdb_prompt $" { ++ pass "$test" ++ } ++ } ++ ++ # ".*sleep.*clone.*" would fail on s390x as bt stops at START_THREAD there. ++ if {[string equal $threadtype threaded]} { ++ gdb_test "thread apply all bt" ".*sleep.*start_thread.*" "$threadtype: attach1 to stopped bt" ++ } else { ++ gdb_test "bt" ".*sleep.*main.*" "$threadtype: attach1 to stopped bt" ++ } ++ ++ # Exit and detach the process. ++ ++ gdb_exit ++ ++ # Avoid some race: ++ sleep 2 ++ ++ if [catch {open /proc/${testpid}/status r} fileid] { ++ set line2 "NOTFOUND" ++ } else { ++ gets $fileid line1; ++ gets $fileid line2; ++ close $fileid; ++ } ++ ++ set test "$threadtype: attach1, exit leaves process stopped" ++ if {[string match "*(stopped)*" $line2]} { ++ pass $test ++ } else { ++ fail $test ++ } ++ ++ # At this point, the process should still be stopped ++ ++ gdb_start ++ gdb_reinitialize_dir $srcdir/$subdir ++ gdb_load ${binfile} ++ ++ # Verify that we can attach to the process just by giving the ++ # process ID. + + set test "$threadtype: attach2 to stopped, after setting file" + gdb_test_multiple "attach $testpid" "$test" { +Index: gdb-6.8.50.20090209/gdb/testsuite/gdb.threads/attachstop-mt.exp +=================================================================== +--- gdb-6.8.50.20090209.orig/gdb/testsuite/gdb.threads/attachstop-mt.exp 2009-01-03 06:58:07.000000000 +0100 ++++ gdb-6.8.50.20090209/gdb/testsuite/gdb.threads/attachstop-mt.exp 2009-02-09 16:12:41.000000000 +0100 +@@ -176,12 +176,23 @@ gdb_test "bt" ".*sleep.*(func|main).*" " + # Exit and detach the process. + gdb_exit + +-# Stop the program +-remote_exec build "kill -s STOP ${testpid}" +- + # No race + sleep 2 + ++set fileid3 [open $status2 r]; ++gets $fileid3 line1; ++gets $fileid3 line2; ++close $fileid3; ++ ++set test "attach3, exit leaves process stopped" ++if {[string match "*(stopped)*" $line2]} { ++ pass $test ++} else { ++ fail $test ++} ++ ++# At this point, the process should still be stopped ++ + # Continue the test as we would hit another expected bug regarding + # Program received signal SIGSTOP, Stopped (signal). + # across NPTL threads. diff --git a/gdb-6.8-bz254229-gcore-prpsinfo.patch b/gdb-6.8-bz254229-gcore-prpsinfo.patch new file mode 100644 index 0000000..c2d79be --- /dev/null +++ b/gdb-6.8-bz254229-gcore-prpsinfo.patch @@ -0,0 +1,351 @@ +Index: gdb-6.8.50.20081209/bfd/elf-bfd.h +=================================================================== +--- gdb-6.8.50.20081209.orig/bfd/elf-bfd.h 2008-12-03 15:50:57.000000000 +0100 ++++ gdb-6.8.50.20081209/bfd/elf-bfd.h 2008-12-10 01:35:08.000000000 +0100 +@@ -2154,7 +2154,7 @@ extern Elf_Internal_Phdr * _bfd_elf_find + extern char *elfcore_write_note + (bfd *, char *, int *, const char *, int, const void *, int); + extern char *elfcore_write_prpsinfo +- (bfd *, char *, int *, const char *, const char *); ++ (bfd *, char *, int *, void *, const char *, const char *); + extern char *elfcore_write_prstatus + (bfd *, char *, int *, long, int, const void *); + extern char * elfcore_write_pstatus +Index: gdb-6.8.50.20081209/bfd/elf.c +=================================================================== +--- gdb-6.8.50.20081209.orig/bfd/elf.c 2008-12-03 15:50:57.000000000 +0100 ++++ gdb-6.8.50.20081209/bfd/elf.c 2008-12-10 01:35:08.000000000 +0100 +@@ -8345,6 +8345,7 @@ char * + elfcore_write_prpsinfo (bfd *abfd, + char *buf, + int *bufsiz, ++ void *info, + const char *fname, + const char *psargs) + { +@@ -8371,9 +8372,15 @@ elfcore_write_prpsinfo (bfd *abfd, + int note_type = NT_PRPSINFO; + #endif + +- memset (&data, 0, sizeof (data)); +- strncpy (data.pr_fname, fname, sizeof (data.pr_fname)); +- strncpy (data.pr_psargs, psargs, sizeof (data.pr_psargs)); ++ if (info) ++ memcpy (&data, info, sizeof (data)); ++ else ++ { ++ memset (&data, 0, sizeof (data)); ++ strncpy (data.pr_fname, fname, sizeof (data.pr_fname)); ++ strncpy (data.pr_psargs, psargs, sizeof (data.pr_psargs)); ++ } ++ + return elfcore_write_note (abfd, buf, bufsiz, + note_name, note_type, &data, sizeof (data)); + } +@@ -8388,9 +8395,15 @@ elfcore_write_prpsinfo (bfd *abfd, + int note_type = NT_PRPSINFO; + #endif + +- memset (&data, 0, sizeof (data)); +- strncpy (data.pr_fname, fname, sizeof (data.pr_fname)); +- strncpy (data.pr_psargs, psargs, sizeof (data.pr_psargs)); ++ if (info) ++ memcpy (&data, info, sizeof (data)); ++ else ++ { ++ memset (&data, 0, sizeof (data)); ++ strncpy (data.pr_fname, fname, sizeof (data.pr_fname)); ++ strncpy (data.pr_psargs, psargs, sizeof (data.pr_psargs)); ++ } ++ + return elfcore_write_note (abfd, buf, bufsiz, + note_name, note_type, &data, sizeof (data)); + } +Index: gdb-6.8.50.20081209/gdb/amd64-linux-nat.c +=================================================================== +--- gdb-6.8.50.20081209.orig/gdb/amd64-linux-nat.c 2008-12-10 01:28:28.000000000 +0100 ++++ gdb-6.8.50.20081209/gdb/amd64-linux-nat.c 2008-12-10 01:35:08.000000000 +0100 +@@ -139,6 +139,7 @@ static int amd64_linux_gregset32_reg_off + + static char * + amd64_linux_elfcore_write_prpsinfo (bfd *abfd, char *buf, int *bufsiz, ++ void *info, + const char *fname, const char *psargs) + { + if (gdbarch_ptr_bit(current_gdbarch) == 32) +@@ -148,14 +149,20 @@ amd64_linux_elfcore_write_prpsinfo (bfd + struct elf_prpsinfo32 data; + note_type = NT_PRPSINFO; + +- memset (&data, 0, sizeof (data)); +- strncpy (data.pr_fname, fname, sizeof (data.pr_fname)); +- strncpy (data.pr_psargs, psargs, sizeof (data.pr_psargs)); ++ if (info) ++ memcpy (&data, info, sizeof (data)); ++ else ++ { ++ memset (&data, 0, sizeof (data)); ++ strncpy (data.pr_fname, fname, sizeof (data.pr_fname)); ++ strncpy (data.pr_psargs, psargs, sizeof (data.pr_psargs)); ++ } ++ + return elfcore_write_note (abfd, buf, bufsiz, + note_name, note_type, &data, sizeof (data)); + } + else +- return elfcore_write_prpsinfo (abfd, buf, bufsiz, fname, psargs); ++ return elfcore_write_prpsinfo (abfd, buf, bufsiz, info, fname, psargs); + } + + static void +Index: gdb-6.8.50.20081209/gdb/fbsd-nat.c +=================================================================== +--- gdb-6.8.50.20081209.orig/gdb/fbsd-nat.c 2008-10-28 16:22:12.000000000 +0100 ++++ gdb-6.8.50.20081209/gdb/fbsd-nat.c 2008-12-10 01:35:08.000000000 +0100 +@@ -210,6 +210,7 @@ fbsd_make_corefile_notes (bfd *obfd, int + psargs = reconcat (psargs, psargs, " ", get_inferior_args (), NULL); + + note_data = elfcore_write_prpsinfo (obfd, note_data, note_size, ++ NULL, + fname, psargs); + } + +Index: gdb-6.8.50.20081209/gdb/linux-nat.c +=================================================================== +--- gdb-6.8.50.20081209.orig/gdb/linux-nat.c 2008-12-10 01:28:14.000000000 +0100 ++++ gdb-6.8.50.20081209/gdb/linux-nat.c 2008-12-10 01:35:25.000000000 +0100 +@@ -53,6 +53,7 @@ + #include + #include "gdb_dirent.h" + #include "xml-support.h" ++#include "gdb_procfs32.h" /* for struct elf_prpsinfo32 */ + + #ifdef HAVE_PERSONALITY + # include +@@ -216,7 +217,7 @@ static LONGEST (*super_xfer_partial) (st + /* This functions make elfcore note sections. + They may get overriden by code adjusting data for multi-target builds. */ + char *(*linux_elfcore_write_prpsinfo) +- (bfd *, char *, int *, const char *, const char *) = elfcore_write_prpsinfo; ++ (bfd *, char *, int *, void *, const char *, const char *) = elfcore_write_prpsinfo; + char *(*linux_elfcore_write_prstatus) + (bfd *, char *, int *, long, int, const void *) = elfcore_write_prstatus; + static char * +@@ -3614,6 +3615,159 @@ linux_nat_corefile_thread_callback (stru + return 0; + } + ++/* Should be always true for Linux */ ++#define HAVE_PRPSINFO_T 1 ++ ++#if defined (HAVE_PRPSINFO_T) ++ ++/* Fills struct elf_prpsinfo{32,64} as much as possible, imitate Linux kernel ++ binfmt_elf.c. Unknown values are filled with zeroes. The structure is ++ malloced. */ ++ ++static void* ++fill_prpsinfo (void) ++{ ++ struct stat sb; ++ char filename[sizeof ("/proc//cmdline") + sizeof (int) * 3 + 2]; ++ char buf[1024]; ++ char proc_state[5]; ++ char proc_cmdline[sizeof (((struct elf_prpsinfo*)0)->pr_psargs) + 1]; ++ unsigned flags; ++ long proc_nice; ++ unsigned proc_ppid; ++ unsigned proc_pgid; ++ unsigned proc_sid; ++ pid_t pid; ++ int fd, n; ++ char *cp, *proc_comm, *state_s; ++ /* String comes from Linux kernel binfmt_elf.c FILL_PSINFO but it is already ++ obsolete there to TASK_* constants. */ ++ const char state_string[] = "RSDTZW"; ++ int state_num; ++ ++ /* Get /proc/$PID/stat. */ ++ pid = ptid_get_pid (inferior_ptid); ++ sprintf (filename, "/proc/%u/stat", (unsigned)pid); ++ fd = open (filename, O_RDONLY); ++ if (fd < 0) ++ return NULL; ++ fstat (fd, &sb); /* No error checking (can it ever happen?). */ ++ n = read (fd, buf, sizeof (buf) - 1); ++ close (fd); ++ if (n < 0) ++ return NULL; ++ buf[n] = 0; ++ ++ cp = strrchr (buf, ')'); /* Split into "PID (COMM" and "". */ ++ if (!cp) ++ return NULL; ++ *cp = 0; ++ ++ /* Grab COMM. */ ++ proc_comm = strchr (buf, '('); ++ if (!proc_comm) ++ return NULL; ++ proc_comm++; ++ ++ /* Read /proc/$PID/cmdline. */ ++ proc_cmdline[0] = 0; ++ strcpy (strrchr (filename, '/'), "/cmdline"); ++ fd = open (filename, O_RDONLY); ++ if (fd >= 0) ++ { ++ int n; ++ ++ n = read (fd, proc_cmdline, sizeof (proc_cmdline) - 1); ++ if (n < 0) ++ n = 0; ++ proc_cmdline[n] = 0; ++ while (n--) /* Replace NULs with spaces. */ ++ if (proc_cmdline[n] == 0) ++ proc_cmdline[n] = ' '; ++ close (fd); ++ } ++ ++ /* Parse /proc/$PID/stat. */ ++ n = sscanf (cp + 2, /* skip ") " */ ++ "%4s %u " /* state, ppid */ ++ "%u %u %*s %*s " /* pgid, sid, tty, tpgid */ ++ "%u %*s %*s %*s " /* flags, min_flt, cmin_flt, maj_flt */ ++ "%*s " /* cmaj_flt */ ++ "%*s %*s " /* utime, stime */ ++ "%*s %*s %*s " /* cutime, cstime, priority */ ++ "%ld " /* nice */ ++ /*"%*s %*s " timeout, it_real_value */ ++ /*"%lu " start_time */ ++ /*"%lu " vsize */ ++ /*"%lu " rss */ ++ /*"%lu %lu %lu " rss_rlim, start_code, end_code */ ++ /*"%lu %lu %lu " start_stack, kstk_esp, kstk_eip */ ++ /*"%u %u %u %u " signal, blocked, sigignore, sigcatch */ ++ /*"%lu %lu %lu" wchan, nswap, cnswap */ ++ , proc_state, &proc_ppid, ++ &proc_pgid, &proc_sid, ++ &flags, ++ &proc_nice); ++ if (n != 6) ++ return NULL; ++ ++ state_s = strchr (state_string, proc_state[0]); ++ if (state_s != NULL) ++ state_num = state_s - state_string; ++ else ++ { ++ /* 0 means Running, some more unusal state would be better. */ ++ state_num = 0; ++ } ++ ++#if ULONG_MAX > 0xffffffffU ++ /* We skip this code on 32-bit gdb. */ ++ if (gdbarch_ptr_bit (current_gdbarch) == 64) ++ { ++ struct elf_prpsinfo *info = xzalloc (sizeof (*info)); ++ ++ info->pr_state = state_num; ++ info->pr_sname = proc_state[0]; ++ info->pr_zomb = (proc_state[0] == 'Z'); ++ info->pr_nice = proc_nice; ++ info->pr_flag = flags; ++ info->pr_uid = sb.st_uid; ++ info->pr_gid = sb.st_gid; ++ info->pr_pid = pid; ++ info->pr_ppid = proc_ppid; ++ info->pr_pgrp = proc_pgid; ++ info->pr_sid = proc_sid; ++ strncpy (info->pr_fname, proc_comm, sizeof (info->pr_fname)); ++ strncpy (info->pr_psargs, proc_cmdline, sizeof (info->pr_psargs)); ++ ++ return info; ++ } ++#endif ++ if (gdbarch_ptr_bit (current_gdbarch) == 32) ++ { ++ struct elf_prpsinfo32 *info = xzalloc (sizeof (*info)); ++ ++ info->pr_state = state_num; ++ info->pr_sname = proc_state[0]; ++ info->pr_zomb = (proc_state[0] == 'Z'); ++ info->pr_nice = proc_nice; ++ info->pr_flag = flags; ++ info->pr_uid = sb.st_uid; ++ info->pr_gid = sb.st_gid; ++ info->pr_pid = pid; ++ info->pr_ppid = proc_ppid; ++ info->pr_pgrp = proc_pgid; ++ info->pr_sid = proc_sid; ++ strncpy (info->pr_fname, proc_comm, sizeof (info->pr_fname)); ++ strncpy (info->pr_psargs, proc_cmdline, sizeof (info->pr_psargs)); ++ ++ return info; ++ } ++ ++ return NULL; ++} ++#endif ++ + /* Fills the "to_make_corefile_note" target vector. Builds the note + section for a corefile, and returns it in a malloc buffer. */ + +@@ -3633,8 +3787,14 @@ linux_nat_make_corefile_notes (bfd *obfd + + if (get_exec_file (0)) + { ++#if defined (HAVE_PRPSINFO_T) ++ void *data = fill_prpsinfo (); ++#define DATAPTR data ++#else ++#define DATAPTR NULL + strncpy (fname, strrchr (get_exec_file (0), '/') + 1, sizeof (fname)); + strncpy (psargs, get_exec_file (0), sizeof (psargs)); ++#endif + if (get_inferior_args ()) + { + char *string_end; +@@ -3650,9 +3810,15 @@ linux_nat_make_corefile_notes (bfd *obfd + psargs_end - string_end); + } + } +- note_data = (char *) linux_elfcore_write_prpsinfo (obfd, note_data, +- note_size, fname, ++ note_data = (char *) linux_elfcore_write_prpsinfo (obfd, ++ note_data, note_size, ++ DATAPTR, ++ fname, + psargs); ++#if defined (HAVE_PRPSINFO_T) ++ xfree (DATAPTR); ++#endif ++#undef DATAPTR + } + + /* Dump information for threads. */ +Index: gdb-6.8.50.20081209/gdb/linux-nat.h +=================================================================== +--- gdb-6.8.50.20081209.orig/gdb/linux-nat.h 2008-12-10 01:27:33.000000000 +0100 ++++ gdb-6.8.50.20081209/gdb/linux-nat.h 2008-12-10 01:35:08.000000000 +0100 +@@ -138,7 +138,7 @@ struct siginfo *linux_nat_get_siginfo (p + /* These functions make elfcore note sections. + They may get overriden by code adjusting data for multi-target builds. */ + extern char *(*linux_elfcore_write_prpsinfo) +- (bfd *, char *, int *, const char *, const char *); ++ (bfd *, char *, int *, void *, const char *, const char *); + extern char *(*linux_elfcore_write_prstatus) + (bfd *, char *, int *, long, int, const void *); + extern char *(*linux_elfcore_write_prfpreg) +Index: gdb-6.8.50.20081209/gdb/procfs.c +=================================================================== +--- gdb-6.8.50.20081209.orig/gdb/procfs.c 2008-11-09 12:27:17.000000000 +0100 ++++ gdb-6.8.50.20081209/gdb/procfs.c 2008-12-10 01:35:08.000000000 +0100 +@@ -6181,6 +6181,7 @@ procfs_make_note_section (bfd *obfd, int + note_data = (char *) elfcore_write_prpsinfo (obfd, + note_data, + note_size, ++ NULL, + fname, + psargs); + diff --git a/gdb-6.8-bz436037-reg-no-longer-active.patch b/gdb-6.8-bz436037-reg-no-longer-active.patch new file mode 100644 index 0000000..e03d45b --- /dev/null +++ b/gdb-6.8-bz436037-reg-no-longer-active.patch @@ -0,0 +1,24 @@ +diff -d -urpN src.0/gdb/valops.c src.1/gdb/valops.c +--- src.0/gdb/valops.c 2008-07-27 04:00:03.000000000 +0200 ++++ src.1/gdb/valops.c 2008-07-31 15:17:42.000000000 +0200 +@@ -813,10 +813,18 @@ value_assign (struct value *toval, struc + struct frame_info *frame; + int value_reg; + +- /* Figure out which frame this is in currently. */ +- frame = frame_find_by_id (VALUE_FRAME_ID (toval)); + value_reg = VALUE_REGNUM (toval); + ++ /* Figure out which frame this is in currently. */ ++ frame = frame_find_by_id (VALUE_FRAME_ID (toval)); ++ /* "set $reg+=1" should work on programs with no debug info, ++ but frame_find_by_id returns NULL here (RH bug 436037). ++ Use current frame, it represents CPU state in this case. ++ If frame_find_by_id is changed to do it internally ++ (it is contemplated there), remove this. */ ++ if (!frame) ++ frame = get_current_frame (); ++ /* Probably never happens. */ + if (!frame) + error (_("Value being assigned to is no longer active.")); + diff --git a/gdb-6.8-bz442765-threaded-exec-test.patch b/gdb-6.8-bz442765-threaded-exec-test.patch new file mode 100644 index 0000000..986894d --- /dev/null +++ b/gdb-6.8-bz442765-threaded-exec-test.patch @@ -0,0 +1,173 @@ +Test various forms of threads tracking across exec(2). + +diff -up -u -X /root/jkratoch/.diffi.list -rup gdb-6.8/gdb/testsuite/gdb.threads/threaded-exec.c gdb-6.8-patched/gdb/testsuite/gdb.threads/threaded-exec.c +--- gdb-6.8/gdb/testsuite/gdb.threads/threaded-exec.c 2008-04-16 17:05:19.000000000 -0400 ++++ gdb-6.8-patched/gdb/testsuite/gdb.threads/threaded-exec.c 2008-04-16 14:43:50.000000000 -0400 +@@ -18,21 +18,95 @@ + Boston, MA 02111-1307, USA. */ + + #include +-#include + #include + #include + #include ++#include + ++#ifdef THREADS ++ ++# include + + static void * + threader (void *arg) + { +- return NULL; ++ return NULL; + } + ++#endif ++ + int +-main (void) ++main (int argc, char **argv) + { ++ char *exec_nothreads, *exec_threads, *cmd; ++ int phase; ++ char phase_s[8]; ++ ++ setbuf (stdout, NULL); ++ ++ if (argc != 4) ++ { ++ fprintf (stderr, "%s \n", argv[0]); ++ return 1; ++ } ++ ++#ifdef THREADS ++ puts ("THREADS: Y"); ++#else ++ puts ("THREADS: N"); ++#endif ++ exec_nothreads = argv[1]; ++ printf ("exec_nothreads: %s\n", exec_nothreads); ++ exec_threads = argv[2]; ++ printf ("exec_threads: %s\n", exec_threads); ++ phase = atoi (argv[3]); ++ printf ("phase: %d\n", phase); ++ ++ /* Phases: threading ++ 0: N -> N ++ 1: N -> Y ++ 2: Y -> Y ++ 3: Y -> N ++ 4: N -> exit */ ++ ++ cmd = NULL; ++ ++#ifndef THREADS ++ switch (phase) ++ { ++ case 0: ++ cmd = exec_nothreads; ++ break; ++ case 1: ++ cmd = exec_threads; ++ break; ++ case 2: ++ fprintf (stderr, "%s: We should have threads for phase %d!\n", argv[0], ++ phase); ++ return 1; ++ case 3: ++ fprintf (stderr, "%s: We should have threads for phase %d!\n", argv[0], ++ phase); ++ return 1; ++ case 4: ++ return 0; ++ default: ++ assert (0); ++ } ++#else /* THREADS */ ++ switch (phase) ++ { ++ case 0: ++ fprintf (stderr, "%s: We should not have threads for phase %d!\n", ++ argv[0], phase); ++ return 1; ++ case 1: ++ fprintf (stderr, "%s: We should not have threads for phase %d!\n", ++ argv[0], phase); ++ return 1; ++ case 2: ++ cmd = exec_threads; ++ { + pthread_t t1; + int i; + +@@ -40,7 +114,34 @@ main (void) + assert (i == 0); + i = pthread_join (t1, NULL); + assert (i == 0); ++ } ++ break; ++ case 3: ++ cmd = exec_nothreads; ++ { ++ pthread_t t1; ++ int i; ++ ++ i = pthread_create (&t1, NULL, threader, (void *) NULL); ++ assert (i == 0); ++ i = pthread_join (t1, NULL); ++ assert (i == 0); ++ } ++ break; ++ case 4: ++ fprintf (stderr, "%s: We should not have threads for phase %d!\n", ++ argv[0], phase); ++ return 1; ++ default: ++ assert (0); ++ } ++#endif /* THREADS */ ++ ++ assert (cmd != NULL); ++ ++ phase++; ++ snprintf (phase_s, sizeof phase_s, "%d", phase); + +- execl ("/bin/true", "/bin/true", NULL); +- abort (); ++ execl (cmd, cmd, exec_nothreads, exec_threads, phase_s, NULL); ++ assert (0); + } +diff -up -u -X /root/jkratoch/.diffi.list -rup gdb-6.8/gdb/testsuite/gdb.threads/threaded-exec.exp gdb-6.8-patched/gdb/testsuite/gdb.threads/threaded-exec.exp +--- gdb-6.8/gdb/testsuite/gdb.threads/threaded-exec.exp 2008-04-16 17:05:19.000000000 -0400 ++++ gdb-6.8-patched/gdb/testsuite/gdb.threads/threaded-exec.exp 2008-04-16 14:42:49.000000000 -0400 +@@ -20,9 +20,14 @@ + + set testfile threaded-exec + set srcfile ${testfile}.c +-set binfile ${objdir}/${subdir}/${testfile} ++set binfile_nothreads ${objdir}/${subdir}/${testfile}N ++set binfile_threads ${objdir}/${subdir}/${testfile}Y + +-if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable []] != "" } { ++if {[gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile_nothreads}" executable {additional_flags=-UTHREADS}] != "" } { ++ return -1 ++} ++ ++if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile_threads}" executable {additional_flags=-DTHREADS}] != "" } { + return -1 + } + +@@ -30,9 +35,9 @@ gdb_exit + gdb_start + gdb_reinitialize_dir $srcdir/$subdir + +-gdb_load ${binfile} ++gdb_load ${binfile_nothreads} + +-gdb_run_cmd ++gdb_run_cmd ${binfile_nothreads} ${binfile_threads} 0 + + gdb_test_multiple {} "Program exited" { + -re "\r\nProgram exited normally.\r\n$gdb_prompt $" { diff --git a/gdb-6.8-bz457187-largefile.patch b/gdb-6.8-bz457187-largefile.patch new file mode 100644 index 0000000..6e297d7 --- /dev/null +++ b/gdb-6.8-bz457187-largefile.patch @@ -0,0 +1,423 @@ +gdb/ +2009-03-02 Jan Kratochvil + + * configure.ac: Call AC_SYS_LARGEFILE. + * config.in: Regenerate. + * configure: Regenerate. + +diff -up -rup gdb-orig/configure.ac gdb/configure.ac +--- ./gdb-orig/configure.ac 2009-03-02 23:39:01.000000000 +0100 ++++ ./gdb/configure.ac 2009-03-02 23:40:46.000000000 +0100 +@@ -30,6 +30,7 @@ AC_GNU_SOURCE + AC_AIX + AC_ISC_POSIX + gl_EARLY ++AC_SYS_LARGEFILE + AM_PROG_CC_STDC + + AC_CONFIG_AUX_DIR(..) +diff -up -rup gdb-orig/config.in gdb/config.in +--- ./gdb-orig/config.in 2009-03-02 23:39:01.000000000 +0100 ++++ ./gdb/config.in 2009-03-02 23:40:53.000000000 +0100 +@@ -725,6 +725,9 @@ + # undef _ALL_SOURCE + #endif + ++/* Number of bits in a file offset, on hosts where this is settable. */ ++#undef _FILE_OFFSET_BITS ++ + /* Enable GNU extensions on systems that have them. */ + #ifndef _GNU_SOURCE + # undef _GNU_SOURCE +@@ -734,6 +737,9 @@ + problem on IRIX 5. */ + #undef _KMEMUSER + ++/* Define for large files, on AIX-style hosts. */ ++#undef _LARGE_FILES ++ + /* Define to 1 if on MINIX. */ + #undef _MINIX + +diff -up -rup gdb-orig/configure gdb/configure +--- ./gdb-orig/configure 2009-03-02 23:39:01.000000000 +0100 ++++ ./gdb/configure 2009-03-02 23:40:49.000000000 +0100 +@@ -862,6 +862,7 @@ Optional Features: + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-maintainer-mode enable make rules and dependencies not useful + (and sometimes confusing) to the casual installer ++ --disable-largefile omit support for large files + --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors + --enable-targets alternative target configurations +@@ -3313,6 +3314,370 @@ _ACEOF + + + ++# Check whether --enable-largefile or --disable-largefile was given. ++if test "${enable_largefile+set}" = set; then ++ enableval="$enable_largefile" ++ ++fi; ++if test "$enable_largefile" != no; then ++ ++ echo "$as_me:$LINENO: checking for special C compiler options needed for large files" >&5 ++echo $ECHO_N "checking for special C compiler options needed for large files... $ECHO_C" >&6 ++if test "${ac_cv_sys_largefile_CC+set}" = set; then ++ echo $ECHO_N "(cached) $ECHO_C" >&6 ++else ++ ac_cv_sys_largefile_CC=no ++ if test "$GCC" != yes; then ++ ac_save_CC=$CC ++ while :; do ++ # IRIX 6.2 and later do not support large files by default, ++ # so use the C compiler's -n32 option if that helps. ++ cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++#include ++ /* Check that off_t can represent 2**63 - 1 correctly. ++ We can't simply define LARGE_OFF_T to be 9223372036854775807, ++ since some C++ compilers masquerading as C compilers ++ incorrectly reject 9223372036854775807. */ ++#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) ++ int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 ++ && LARGE_OFF_T % 2147483647 == 1) ++ ? 1 : -1]; ++int ++main () ++{ ++ ++ ; ++ return 0; ++} ++_ACEOF ++ rm -f conftest.$ac_objext ++if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ++ (eval $ac_compile) 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } && ++ { ac_try='test -z "$ac_c_werror_flag" ++ || test ! -s conftest.err' ++ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 ++ (eval $ac_try) 2>&5 ++ ac_status=$? ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); }; } && ++ { ac_try='test -s conftest.$ac_objext' ++ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 ++ (eval $ac_try) 2>&5 ++ ac_status=$? ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); }; }; then ++ break ++else ++ echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++fi ++rm -f conftest.err conftest.$ac_objext ++ CC="$CC -n32" ++ rm -f conftest.$ac_objext ++if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ++ (eval $ac_compile) 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } && ++ { ac_try='test -z "$ac_c_werror_flag" ++ || test ! -s conftest.err' ++ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 ++ (eval $ac_try) 2>&5 ++ ac_status=$? ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); }; } && ++ { ac_try='test -s conftest.$ac_objext' ++ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 ++ (eval $ac_try) 2>&5 ++ ac_status=$? ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); }; }; then ++ ac_cv_sys_largefile_CC=' -n32'; break ++else ++ echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++fi ++rm -f conftest.err conftest.$ac_objext ++ break ++ done ++ CC=$ac_save_CC ++ rm -f conftest.$ac_ext ++ fi ++fi ++echo "$as_me:$LINENO: result: $ac_cv_sys_largefile_CC" >&5 ++echo "${ECHO_T}$ac_cv_sys_largefile_CC" >&6 ++ if test "$ac_cv_sys_largefile_CC" != no; then ++ CC=$CC$ac_cv_sys_largefile_CC ++ fi ++ ++ echo "$as_me:$LINENO: checking for _FILE_OFFSET_BITS value needed for large files" >&5 ++echo $ECHO_N "checking for _FILE_OFFSET_BITS value needed for large files... $ECHO_C" >&6 ++if test "${ac_cv_sys_file_offset_bits+set}" = set; then ++ echo $ECHO_N "(cached) $ECHO_C" >&6 ++else ++ while :; do ++ ac_cv_sys_file_offset_bits=no ++ cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++#include ++ /* Check that off_t can represent 2**63 - 1 correctly. ++ We can't simply define LARGE_OFF_T to be 9223372036854775807, ++ since some C++ compilers masquerading as C compilers ++ incorrectly reject 9223372036854775807. */ ++#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) ++ int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 ++ && LARGE_OFF_T % 2147483647 == 1) ++ ? 1 : -1]; ++int ++main () ++{ ++ ++ ; ++ return 0; ++} ++_ACEOF ++rm -f conftest.$ac_objext ++if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ++ (eval $ac_compile) 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } && ++ { ac_try='test -z "$ac_c_werror_flag" ++ || test ! -s conftest.err' ++ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 ++ (eval $ac_try) 2>&5 ++ ac_status=$? ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); }; } && ++ { ac_try='test -s conftest.$ac_objext' ++ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 ++ (eval $ac_try) 2>&5 ++ ac_status=$? ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); }; }; then ++ break ++else ++ echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++fi ++rm -f conftest.err conftest.$ac_objext conftest.$ac_ext ++ cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++#define _FILE_OFFSET_BITS 64 ++#include ++ /* Check that off_t can represent 2**63 - 1 correctly. ++ We can't simply define LARGE_OFF_T to be 9223372036854775807, ++ since some C++ compilers masquerading as C compilers ++ incorrectly reject 9223372036854775807. */ ++#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) ++ int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 ++ && LARGE_OFF_T % 2147483647 == 1) ++ ? 1 : -1]; ++int ++main () ++{ ++ ++ ; ++ return 0; ++} ++_ACEOF ++rm -f conftest.$ac_objext ++if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ++ (eval $ac_compile) 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } && ++ { ac_try='test -z "$ac_c_werror_flag" ++ || test ! -s conftest.err' ++ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 ++ (eval $ac_try) 2>&5 ++ ac_status=$? ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); }; } && ++ { ac_try='test -s conftest.$ac_objext' ++ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 ++ (eval $ac_try) 2>&5 ++ ac_status=$? ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); }; }; then ++ ac_cv_sys_file_offset_bits=64; break ++else ++ echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++fi ++rm -f conftest.err conftest.$ac_objext conftest.$ac_ext ++ break ++done ++fi ++echo "$as_me:$LINENO: result: $ac_cv_sys_file_offset_bits" >&5 ++echo "${ECHO_T}$ac_cv_sys_file_offset_bits" >&6 ++if test "$ac_cv_sys_file_offset_bits" != no; then ++ ++cat >>confdefs.h <<_ACEOF ++#define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits ++_ACEOF ++ ++fi ++rm -f conftest* ++ echo "$as_me:$LINENO: checking for _LARGE_FILES value needed for large files" >&5 ++echo $ECHO_N "checking for _LARGE_FILES value needed for large files... $ECHO_C" >&6 ++if test "${ac_cv_sys_large_files+set}" = set; then ++ echo $ECHO_N "(cached) $ECHO_C" >&6 ++else ++ while :; do ++ ac_cv_sys_large_files=no ++ cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++#include ++ /* Check that off_t can represent 2**63 - 1 correctly. ++ We can't simply define LARGE_OFF_T to be 9223372036854775807, ++ since some C++ compilers masquerading as C compilers ++ incorrectly reject 9223372036854775807. */ ++#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) ++ int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 ++ && LARGE_OFF_T % 2147483647 == 1) ++ ? 1 : -1]; ++int ++main () ++{ ++ ++ ; ++ return 0; ++} ++_ACEOF ++rm -f conftest.$ac_objext ++if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ++ (eval $ac_compile) 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } && ++ { ac_try='test -z "$ac_c_werror_flag" ++ || test ! -s conftest.err' ++ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 ++ (eval $ac_try) 2>&5 ++ ac_status=$? ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); }; } && ++ { ac_try='test -s conftest.$ac_objext' ++ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 ++ (eval $ac_try) 2>&5 ++ ac_status=$? ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); }; }; then ++ break ++else ++ echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++fi ++rm -f conftest.err conftest.$ac_objext conftest.$ac_ext ++ cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++#define _LARGE_FILES 1 ++#include ++ /* Check that off_t can represent 2**63 - 1 correctly. ++ We can't simply define LARGE_OFF_T to be 9223372036854775807, ++ since some C++ compilers masquerading as C compilers ++ incorrectly reject 9223372036854775807. */ ++#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) ++ int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 ++ && LARGE_OFF_T % 2147483647 == 1) ++ ? 1 : -1]; ++int ++main () ++{ ++ ++ ; ++ return 0; ++} ++_ACEOF ++rm -f conftest.$ac_objext ++if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ++ (eval $ac_compile) 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } && ++ { ac_try='test -z "$ac_c_werror_flag" ++ || test ! -s conftest.err' ++ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 ++ (eval $ac_try) 2>&5 ++ ac_status=$? ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); }; } && ++ { ac_try='test -s conftest.$ac_objext' ++ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 ++ (eval $ac_try) 2>&5 ++ ac_status=$? ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); }; }; then ++ ac_cv_sys_large_files=1; break ++else ++ echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++fi ++rm -f conftest.err conftest.$ac_objext conftest.$ac_ext ++ break ++done ++fi ++echo "$as_me:$LINENO: result: $ac_cv_sys_large_files" >&5 ++echo "${ECHO_T}$ac_cv_sys_large_files" >&6 ++if test "$ac_cv_sys_large_files" != no; then ++ ++cat >>confdefs.h <<_ACEOF ++#define _LARGE_FILES $ac_cv_sys_large_files ++_ACEOF ++ ++fi ++rm -f conftest* ++fi ++ + + + diff --git a/gdb-6.8-bz466901-backtrace-full-prelinked.patch b/gdb-6.8-bz466901-backtrace-full-prelinked.patch new file mode 100644 index 0000000..9a96ac8 --- /dev/null +++ b/gdb-6.8-bz466901-backtrace-full-prelinked.patch @@ -0,0 +1,488 @@ +Fix resolving of variables at locations lists in prelinked libs (BZ 466901). + +Index: gdb-6.8.50.20081128/gdb/dwarf2loc.c +=================================================================== +--- gdb-6.8.50.20081128.orig/gdb/dwarf2loc.c 2008-12-08 11:00:45.000000000 +0100 ++++ gdb-6.8.50.20081128/gdb/dwarf2loc.c 2008-12-08 18:02:49.000000000 +0100 +@@ -55,7 +55,9 @@ find_location_expression (struct dwarf2_ + CORE_ADDR low, high; + gdb_byte *loc_ptr, *buf_end; + int length; +- struct objfile *objfile = dwarf2_per_cu_objfile (baton->per_cu); ++ struct objfile *objfile1 = dwarf2_per_cu_objfile (baton->per_cu); ++ struct objfile *objfile = objfile1->separate_debug_objfile ++ ? objfile1->separate_debug_objfile : objfile1; + struct gdbarch *gdbarch = get_objfile_arch (objfile); + unsigned int addr_size = dwarf2_per_cu_addr_size (baton->per_cu); + CORE_ADDR base_mask = ~(~(CORE_ADDR)1 << (addr_size * 8 - 1)); +Index: gdb-6.8.50.20081128/gdb/testsuite/gdb.dwarf2/dw2-loclist-prelinked.exp +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8.50.20081128/gdb/testsuite/gdb.dwarf2/dw2-loclist-prelinked.exp 2008-12-08 18:00:43.000000000 +0100 +@@ -0,0 +1,102 @@ ++# Copyright 2008 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++# Minimal DWARF-2 unit test ++ ++# This test can only be run on i386/x86_64 targets which support DWARF-2. ++# For now pick a sampling of likely targets. ++if {(![istarget *-*-linux*] ++ && ![istarget *-*-gnu*] ++ && ![istarget *-*-elf*] ++ && ![istarget *-*-openbsd*]) ++ || (![istarget "i?86-*-*"] && ![istarget "x86_64-*-*"])} { ++ return 0 ++} ++ ++set testfile "dw2-loclist-prelinked" ++set srcfuncfile ${testfile}-func.S ++set binsharedfuncfile ${objdir}/${subdir}/${testfile}.so ++set srcmainfile ${testfile}-main.c ++set binfile ${objdir}/${subdir}/${testfile} ++ ++remote_exec build "rm -f ${binfile}" ++ ++# get the value of gcc_compiled ++if [get_compiler_info ${binfile}] { ++ return -1 ++} ++ ++# This test can only be run on gcc as we use additional_flags=FIXME ++if {$gcc_compiled == 0} { ++ return 0 ++} ++ ++if { [gdb_compile_shlib "${srcdir}/${subdir}/${srcfuncfile}" "${binsharedfuncfile}" {debug additional_flags=-m32}] != "" } { ++ untested "Couldn't compile test library" ++ return -1 ++} ++ ++# The new separate debug info file will be stored in the .debug subdirectory. ++ ++if [gdb_gnu_strip_debug ${binsharedfuncfile}] { ++ # check that you have a recent version of strip and objcopy installed ++ unsupported "cannot produce separate debug info files" ++ return -1 ++} ++ ++if {[catch "system \"/usr/sbin/prelink -qNR --no-exec-shield ${binsharedfuncfile}\""] != 0} { ++ # Maybe we don't have prelink. ++ return -1 ++} ++ ++if { [gdb_compile "${srcdir}/${subdir}/${srcmainfile}" \ ++ "${binfile}" executable [list debug additional_flags=-m32 shlib=${binsharedfuncfile}]] != "" } { ++ return -1 ++} ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++gdb_run_cmd ++ ++gdb_test "" "Program received signal SIGABRT, Aborted..*" "Enter abort()" ++ ++# Incorrect: ++# #0 0x00110430 in __kernel_vsyscall () ++# No symbol table info available. ++# #1 0x003d44c0 in raise () from /lib/libc.so.6 ++# No symbol table info available. ++# #2 0x003d5e88 in abort () from /lib/libc.so.6 ++# No symbol table info available. ++# #3 0x44f10437 in func () at dw2-loclist-prelinked.c:8 ++# i = Could not find the frame base for "func". ++ ++# Correct: ++# #0 0x00110430 in __kernel_vsyscall () ++# No symbol table info available. ++# #1 0x003d44c0 in raise () from /lib/libc.so.6 ++# No symbol table info available. ++# #2 0x003d5e88 in abort () from /lib/libc.so.6 ++# No symbol table info available. ++# #3 0x4ae36437 in func () at dw2-loclist-prelinked.c:8 ++# i = 3827288 ++# #4 0x0804851a in main () at ../../../gdb/testsuite/gdb.dwarf2/dw2-loclist-prelinked-main.c:24 ++# No locals. ++ ++# `abort' can get expressed as `*__GI_abort'. ++gdb_test "bt full" "in \[^ \]*abort \\(.*in func \\(.*\r\n\[\t \]+i = -?\[0-9\].*in main \\(.*" "Backtrace after abort()" +Index: gdb-6.8.50.20081128/gdb/testsuite/gdb.dwarf2/dw2-loclist-prelinked-main.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8.50.20081128/gdb/testsuite/gdb.dwarf2/dw2-loclist-prelinked-main.c 2008-12-08 18:00:43.000000000 +0100 +@@ -0,0 +1,26 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2008 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++/* dw2-loclist-prelinked-func.S */ ++extern void func (void); ++ ++int ++main (void) ++{ ++ func (); ++ return 0; ++} +Index: gdb-6.8.50.20081128/gdb/testsuite/gdb.dwarf2/dw2-loclist-prelinked-func.S +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8.50.20081128/gdb/testsuite/gdb.dwarf2/dw2-loclist-prelinked-func.S 2008-12-08 18:00:43.000000000 +0100 +@@ -0,0 +1,328 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2008 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++/* ++#include ++ ++void ++func (void) ++{ ++ int i; ++ ++ abort (); ++} ++*/ ++ .file "dw2-loclist-prelinked.c" ++ .section .debug_abbrev,"",@progbits ++.Ldebug_abbrev0: ++ .section .debug_info,"",@progbits ++.Ldebug_info0: ++ .section .debug_line,"",@progbits ++.Ldebug_line0: ++ .text ++.Ltext0: ++.globl func ++ .type func, @function ++func: ++.LFB2: ++ .file 1 "dw2-loclist-prelinked.c" ++ .loc 1 5 0 ++ pushl %ebp ++.LCFI0: ++ movl %esp, %ebp ++.LCFI1: ++ subl $24, %esp ++.LCFI2: ++ .loc 1 8 0 ++ call abort ++.LFE2: ++ .size func, .-func ++ .section .debug_frame,"",@progbits ++.Lframe0: ++ .long .LECIE0-.LSCIE0 ++.LSCIE0: ++ .long 0xffffffff ++ .byte 0x1 ++ .string "" ++ .uleb128 0x1 ++ .sleb128 -4 ++ .byte 0x8 ++ .byte 0xc ++ .uleb128 0x4 ++ .uleb128 0x4 ++ .byte 0x88 ++ .uleb128 0x1 ++ .align 4 ++.LECIE0: ++.LSFDE0: ++ .long .LEFDE0-.LASFDE0 ++.LASFDE0: ++ .long .Lframe0 ++ .long .LFB2 ++ .long .LFE2-.LFB2 ++ .byte 0x4 ++ .long .LCFI0-.LFB2 ++ .byte 0xe ++ .uleb128 0x8 ++ .byte 0x85 ++ .uleb128 0x2 ++ .byte 0x4 ++ .long .LCFI1-.LCFI0 ++ .byte 0xd ++ .uleb128 0x5 ++ .align 4 ++.LEFDE0: ++ .text ++.Letext0: ++ .section .debug_loc,"",@progbits ++.Ldebug_loc0: ++.LLST0: ++ .long .LFB2-.Ltext0 ++ .long .LCFI0-.Ltext0 ++ .value 0x2 ++ .byte 0x74 ++ .sleb128 4 ++ .long .LCFI0-.Ltext0 ++ .long .LCFI1-.Ltext0 ++ .value 0x2 ++ .byte 0x74 ++ .sleb128 8 ++ .long .LCFI1-.Ltext0 ++ .long .LFE2-.Ltext0 ++ .value 0x2 ++ .byte 0x75 ++ .sleb128 8 ++ .long 0x0 ++ .long 0x0 ++ .section .debug_info ++ .long 0x94 ++ .value 0x2 ++ .long .Ldebug_abbrev0 ++ .byte 0x4 ++ .uleb128 0x1 ++ .long .LASF10 ++ .byte 0x1 ++ .long .LASF11 ++ .long .LASF12 ++ .long .Ltext0 ++ .long .Letext0 ++ .long .Ldebug_line0 ++ .uleb128 0x2 ++ .byte 0x4 ++ .byte 0x7 ++ .long .LASF0 ++ .uleb128 0x3 ++ .byte 0x4 ++ .byte 0x5 ++ .string "int" ++ .uleb128 0x2 ++ .byte 0x4 ++ .byte 0x5 ++ .long .LASF1 ++ .uleb128 0x2 ++ .byte 0x1 ++ .byte 0x8 ++ .long .LASF2 ++ .uleb128 0x2 ++ .byte 0x2 ++ .byte 0x7 ++ .long .LASF3 ++ .uleb128 0x2 ++ .byte 0x4 ++ .byte 0x7 ++ .long .LASF4 ++ .uleb128 0x2 ++ .byte 0x1 ++ .byte 0x6 ++ .long .LASF5 ++ .uleb128 0x2 ++ .byte 0x2 ++ .byte 0x5 ++ .long .LASF6 ++ .uleb128 0x2 ++ .byte 0x8 ++ .byte 0x5 ++ .long .LASF7 ++ .uleb128 0x2 ++ .byte 0x8 ++ .byte 0x7 ++ .long .LASF8 ++ .uleb128 0x4 ++ .byte 0x4 ++ .byte 0x7 ++ .uleb128 0x2 ++ .byte 0x1 ++ .byte 0x6 ++ .long .LASF9 ++ .uleb128 0x5 ++ .byte 0x1 ++ .long .LASF13 ++ .byte 0x1 ++ .byte 0x5 ++ .byte 0x1 ++ .long .LFB2 ++ .long .LFE2 ++ .long .LLST0 ++ .uleb128 0x6 ++ .string "i" ++ .byte 0x1 ++ .byte 0x6 ++ .long 0x2c ++ .byte 0x2 ++ .byte 0x91 ++ .sleb128 -12 ++ .byte 0x0 ++ .byte 0x0 ++ .section .debug_abbrev ++ .uleb128 0x1 ++ .uleb128 0x11 ++ .byte 0x1 ++ .uleb128 0x25 ++ .uleb128 0xe ++ .uleb128 0x13 ++ .uleb128 0xb ++ .uleb128 0x3 ++ .uleb128 0xe ++ .uleb128 0x1b ++ .uleb128 0xe ++ .uleb128 0x11 ++ .uleb128 0x1 ++ .uleb128 0x12 ++ .uleb128 0x1 ++ .uleb128 0x10 ++ .uleb128 0x6 ++ .byte 0x0 ++ .byte 0x0 ++ .uleb128 0x2 ++ .uleb128 0x24 ++ .byte 0x0 ++ .uleb128 0xb ++ .uleb128 0xb ++ .uleb128 0x3e ++ .uleb128 0xb ++ .uleb128 0x3 ++ .uleb128 0xe ++ .byte 0x0 ++ .byte 0x0 ++ .uleb128 0x3 ++ .uleb128 0x24 ++ .byte 0x0 ++ .uleb128 0xb ++ .uleb128 0xb ++ .uleb128 0x3e ++ .uleb128 0xb ++ .uleb128 0x3 ++ .uleb128 0x8 ++ .byte 0x0 ++ .byte 0x0 ++ .uleb128 0x4 ++ .uleb128 0x24 ++ .byte 0x0 ++ .uleb128 0xb ++ .uleb128 0xb ++ .uleb128 0x3e ++ .uleb128 0xb ++ .byte 0x0 ++ .byte 0x0 ++ .uleb128 0x5 ++ .uleb128 0x2e ++ .byte 0x1 ++ .uleb128 0x3f ++ .uleb128 0xc ++ .uleb128 0x3 ++ .uleb128 0xe ++ .uleb128 0x3a ++ .uleb128 0xb ++ .uleb128 0x3b ++ .uleb128 0xb ++ .uleb128 0x27 ++ .uleb128 0xc ++ .uleb128 0x11 ++ .uleb128 0x1 ++ .uleb128 0x12 ++ .uleb128 0x1 ++ .uleb128 0x40 ++ .uleb128 0x6 ++ .byte 0x0 ++ .byte 0x0 ++ .uleb128 0x6 ++ .uleb128 0x34 ++ .byte 0x0 ++ .uleb128 0x3 ++ .uleb128 0x8 ++ .uleb128 0x3a ++ .uleb128 0xb ++ .uleb128 0x3b ++ .uleb128 0xb ++ .uleb128 0x49 ++ .uleb128 0x13 ++ .uleb128 0x2 ++ .uleb128 0xa ++ .byte 0x0 ++ .byte 0x0 ++ .byte 0x0 ++ .section .debug_pubnames,"",@progbits ++ .long 0x17 ++ .value 0x2 ++ .long .Ldebug_info0 ++ .long 0x98 ++ .long 0x75 ++ .string "func" ++ .long 0x0 ++ .section .debug_aranges,"",@progbits ++ .long 0x1c ++ .value 0x2 ++ .long .Ldebug_info0 ++ .byte 0x4 ++ .byte 0x0 ++ .value 0x0 ++ .value 0x0 ++ .long .Ltext0 ++ .long .Letext0-.Ltext0 ++ .long 0x0 ++ .long 0x0 ++ .section .debug_str,"MS",@progbits,1 ++.LASF7: ++ .string "long long int" ++.LASF0: ++ .string "unsigned int" ++.LASF11: ++ .string "dw2-loclist-prelinked.c" ++.LASF12: ++ .string "gdb-6.8/gdb/testsuite/gdb.dwarf2" ++.LASF4: ++ .string "long unsigned int" ++.LASF8: ++ .string "long long unsigned int" ++.LASF2: ++ .string "unsigned char" ++.LASF9: ++ .string "char" ++.LASF1: ++ .string "long int" ++.LASF3: ++ .string "short unsigned int" ++.LASF5: ++ .string "signed char" ++.LASF10: ++ .string "GNU C 4.3.2 20081007 (Red Hat 4.3.2-6)" ++.LASF13: ++ .string "func" ++.LASF6: ++ .string "short int" ++ .ident "GCC: (GNU) 4.3.2 20081007 (Red Hat 4.3.2-6)" ++ .section .note.GNU-stack,"",@progbits diff --git a/gdb-6.8-constant-watchpoints.patch b/gdb-6.8-constant-watchpoints.patch new file mode 100644 index 0000000..baa242b --- /dev/null +++ b/gdb-6.8-constant-watchpoints.patch @@ -0,0 +1,236 @@ +2008-07-10 Jan Kratochvil + + * breakpoint.c (fetch_watchpoint_value): New comment on unreachable + values. + (watch_command_1): New variable VAL_CHAIN. Refuse constant watchpoints. + * gdbtypes.h (TYPE_CODE_FUNC): New comment regarding pointers to it. + +2008-07-10 Jan Kratochvil + + * gdb.texinfo (Set Watchpoints): Document constant value watchpoints. + +2008-07-10 Jan Kratochvil + + * gdb.base/watchpoint.exp: Call TEST_CONSTANT_WATCHPOINT. + (test_constant_watchpoint): New function. + (test_inaccessible_watchpoint): Cleanup (delete) the watchpoint. + Test also a double-indirection watchpoint. + gdb.base/watchpoint.c (global_ptr_ptr): New variable. + (func4): New testing code for GLOBAL_PTR_PTR. + +Index: gdb-6.8.50.20090209/gdb/breakpoint.c +=================================================================== +--- gdb-6.8.50.20090209.orig/gdb/breakpoint.c 2009-02-09 15:39:01.000000000 +0100 ++++ gdb-6.8.50.20090209/gdb/breakpoint.c 2009-02-09 16:04:10.000000000 +0100 +@@ -769,7 +769,15 @@ is_hardware_watchpoint (struct breakpoin + If VAL_CHAIN is non-NULL, *VAL_CHAIN will be released from the + value chain. The caller must free the values individually. If + VAL_CHAIN is NULL, all generated values will be left on the value +- chain. */ ++ chain. ++ ++ Inferior unreachable values return: ++ Inferior `int *intp = NULL;' with `watch *intp': ++ *VALP is NULL, *RESULTP contains lazy LVAL_MEMORY address 0, *VAL_CHAIN ++ contains the *RESULTP element and also INTP as LVAL_MEMORY. ++ Inferior `int **intpp = NULL;' with `watch **intpp': ++ *VALP is NULL, *RESULTP is NULL, *VAL_CHAIN contains lazy LVAL_MEMORY ++ address 0 and also INTPP as LVAL_MEMORY. */ + + static void + fetch_watchpoint_value (struct expression *exp, struct value **valp, +@@ -5862,7 +5870,7 @@ watch_command_1 (char *arg, int accessfl + struct symtab_and_line sal; + struct expression *exp; + struct block *exp_valid_block; +- struct value *val, *mark; ++ struct value *val, *mark, *val_chain; + struct frame_info *frame; + struct frame_info *prev_frame = NULL; + char *exp_start = NULL; +@@ -5954,6 +5962,27 @@ watch_command_1 (char *arg, int accessfl + exp_valid_block = innermost_block; + mark = value_mark (); + fetch_watchpoint_value (exp, &val, NULL, NULL); ++ ++ /* VALUE_MARK gets us the same value as FETCH_WATCHPOINT_VALUE's VAL_CHAIN ++ parameter. Just this way we do not have to VALUE_FREE the chained VALUEs ++ ourselves. */ ++ for (val_chain = value_mark (); ++ val_chain != mark; ++ val_chain = value_next (val_chain)) ++ if ((VALUE_LVAL (val_chain) == lval_memory ++ && TYPE_CODE (value_type (val_chain)) != TYPE_CODE_FUNC) ++ || VALUE_LVAL (val_chain) == lval_register) ++ break; ++ if (val_chain == mark) ++ { ++ int len; ++ ++ len = exp_end - exp_start; ++ while (len > 0 && isspace (exp_start[len - 1])) ++ len--; ++ error (_("Cannot watch constant value %.*s."), len, exp_start); ++ } ++ /* Break the values chain only after its check above. */ + if (val != NULL) + release_value (val); + +Index: gdb-6.8.50.20090209/gdb/gdbtypes.h +=================================================================== +--- gdb-6.8.50.20090209.orig/gdb/gdbtypes.h 2009-02-09 15:51:57.000000000 +0100 ++++ gdb-6.8.50.20090209/gdb/gdbtypes.h 2009-02-09 16:04:10.000000000 +0100 +@@ -70,7 +70,22 @@ enum type_code + TYPE_CODE_UNION, /* C union or Pascal variant part */ + TYPE_CODE_ENUM, /* Enumeration type */ + TYPE_CODE_FLAGS, /* Bit flags type */ +- TYPE_CODE_FUNC, /* Function type */ ++ ++ /* Function type. It is not a pointer to a function. Function reference ++ by its name (such as `printf') has this type. C automatically converts ++ this function type to a pointer to function for any operation except ++ `sizeof (function_type)' or `&function_type' (unary &). ++ `sizeof (function_type)' is undefined in C. But GCC provides extension ++ (info '(gcc)Pointer Arith') defining its size as 1 byte. DWARF does not ++ define its size but GDB defines the size the GCC compatible way - GDB ++ function MAKE_FUNCTION_TYPE. The address itself is not modifiable. ++ As the function type has size 1 but its real value has `sizeof ++ (CORE_ADDR)' we cannot use NOT_LVAL category because the address would ++ not fit in the VALUE_CONTENTS_RAW container of its VALUE. We use ++ LVAL_MEMORY (and its VALUE_ADDRESS field) for it but we must be careful ++ it is not lvalue, it is the only non-modifiable LVAL_MEMORY. */ ++ TYPE_CODE_FUNC, ++ + TYPE_CODE_INT, /* Integer type */ + + /* Floating type. This is *NOT* a complex type. Beware, there are parts +Index: gdb-6.8.50.20090209/gdb/doc/gdb.texinfo +=================================================================== +--- gdb-6.8.50.20090209.orig/gdb/doc/gdb.texinfo 2009-02-09 16:02:42.000000000 +0100 ++++ gdb-6.8.50.20090209/gdb/doc/gdb.texinfo 2009-02-09 16:04:10.000000000 +0100 +@@ -3480,6 +3480,18 @@ This command prints a list of watchpoint + it is the same as @code{info break} (@pxref{Set Breaks}). + @end table + ++If you watch for a change in a numerically entered address you need to ++dereference it as the address itself is just a constant number which will never ++change. @value{GDBN} refuses to create a watchpoint that watches ++a never-changing value: ++ ++@smallexample ++(@value{GDBP}) watch 0x600850 ++Cannot watch constant value 0x600850. ++(@value{GDBP}) watch *(int *) 0x600850 ++Watchpoint 1: *(int *) 6293584 ++@end smallexample ++ + @value{GDBN} sets a @dfn{hardware watchpoint} if possible. Hardware + watchpoints execute very quickly, and the debugger reports a change in + value at the exact instruction where the change occurs. If @value{GDBN} +Index: gdb-6.8.50.20090209/gdb/testsuite/gdb.base/watchpoint.c +=================================================================== +--- gdb-6.8.50.20090209.orig/gdb/testsuite/gdb.base/watchpoint.c 2008-03-03 14:24:12.000000000 +0100 ++++ gdb-6.8.50.20090209/gdb/testsuite/gdb.base/watchpoint.c 2009-02-09 16:04:10.000000000 +0100 +@@ -40,6 +40,7 @@ struct foo struct1, struct2, *ptr1, *ptr + int doread = 0; + + char *global_ptr; ++char **global_ptr_ptr; + + void marker1 () + { +@@ -118,6 +119,10 @@ func4 () + buf[0] = 3; + global_ptr = buf; + buf[0] = 7; ++ buf[1] = 5; ++ global_ptr_ptr = &global_ptr; ++ buf[0] = 9; ++ global_ptr++; + } + + int main () +Index: gdb-6.8.50.20090209/gdb/testsuite/gdb.base/watchpoint.exp +=================================================================== +--- gdb-6.8.50.20090209.orig/gdb/testsuite/gdb.base/watchpoint.exp 2009-01-03 06:58:03.000000000 +0100 ++++ gdb-6.8.50.20090209/gdb/testsuite/gdb.base/watchpoint.exp 2009-02-09 16:05:03.000000000 +0100 +@@ -641,7 +641,21 @@ proc test_watchpoint_and_breakpoint {} { + } + } + } +- ++ ++proc test_constant_watchpoint {} { ++ global gdb_prompt ++ ++ gdb_test "watch 5" "Cannot watch constant value 5." "number is constant" ++ gdb_test "watch marker1" "Cannot watch constant value marker1." \ ++ "marker1 is constant" ++ gdb_test "watch count + 6" ".*atchpoint \[0-9\]+: count \\+ 6" ++ gdb_test "set \$expr_breakpoint_number = \$bpnum" "" ++ gdb_test "delete \$expr_breakpoint_number" "" ++ gdb_test "watch 7 + count" ".*atchpoint \[0-9\]+: 7 \\+ count" ++ gdb_test "set \$expr_breakpoint_number = \$bpnum" "" ++ gdb_test "delete \$expr_breakpoint_number" "" ++} ++ + proc test_inaccessible_watchpoint {} { + global gdb_prompt + +@@ -662,7 +676,8 @@ proc test_inaccessible_watchpoint {} { + } + + gdb_test "watch *global_ptr" ".*atchpoint \[0-9\]+: \\*global_ptr" +- gdb_test "next" ".*global_ptr = buf.*" ++ gdb_test "set \$global_ptr_breakpoint_number = \$bpnum" "" ++ gdb_test "next" ".*global_ptr = buf.*" "global_ptr next" + gdb_test_multiple "next" "next over ptr init" { + -re ".*atchpoint \[0-9\]+: \\*global_ptr\r\n\r\nOld value = .*\r\nNew value = 3 .*\r\n.*$gdb_prompt $" { + # We can not test for here because NULL may be readable. +@@ -675,6 +690,28 @@ proc test_inaccessible_watchpoint {} { + pass "next over buffer set" + } + } ++ gdb_test "delete \$global_ptr_breakpoint_number" "" ++ gdb_test "watch **global_ptr_ptr" ".*atchpoint \[0-9\]+: \\*\\*global_ptr_ptr" ++ gdb_test "set \$global_ptr_ptr_breakpoint_number = \$bpnum" "" ++ gdb_test "next" ".*global_ptr_ptr = &global_ptr.*" "gloabl_ptr_ptr next" ++ gdb_test_multiple "next" "next over global_ptr_ptr init" { ++ -re ".*atchpoint \[0-9\]+: \\*\\*global_ptr_ptr\r\n\r\nOld value = .*\r\nNew value = 7 .*\r\n.*$gdb_prompt $" { ++ # We can not test for here because NULL may be readable. ++ # This test does rely on *NULL != 7. ++ pass "next over global_ptr_ptr init" ++ } ++ } ++ gdb_test_multiple "next" "next over global_ptr_ptr buffer set" { ++ -re ".*atchpoint \[0-9\]+: \\*\\*global_ptr_ptr\r\n\r\nOld value = 7 .*\r\nNew value = 9 .*\r\n.*$gdb_prompt $" { ++ pass "next over global_ptr_ptr buffer set" ++ } ++ } ++ gdb_test_multiple "next" "next over global_ptr_ptr pointer advance" { ++ -re ".*atchpoint \[0-9\]+: \\*\\*global_ptr_ptr\r\n\r\nOld value = 9 .*\r\nNew value = 5 .*\r\n.*$gdb_prompt $" { ++ pass "next over global_ptr_ptr pointer advance" ++ } ++ } ++ gdb_test "delete \$global_ptr_ptr_breakpoint_number" "" + } + } + +@@ -842,6 +879,17 @@ if [initialize] then { + } + + test_watchpoint_and_breakpoint ++ ++ # See above. ++ if [istarget "mips-idt-*"] then { ++ gdb_exit ++ gdb_start ++ gdb_reinitialize_dir $srcdir/$subdir ++ gdb_load $binfile ++ initialize ++ } ++ ++ test_constant_watchpoint + } + + # Restore old timeout diff --git a/gdb-6.8-ctors-dtors-unique.patch b/gdb-6.8-ctors-dtors-unique.patch new file mode 100644 index 0000000..21e8729 --- /dev/null +++ b/gdb-6.8-ctors-dtors-unique.patch @@ -0,0 +1,73 @@ +--- ./gdb/linespec.c 2008-08-27 00:27:33.000000000 +0200 ++++ ./gdb/linespec.c 2008-08-27 00:53:16.000000000 +0200 +@@ -284,6 +284,15 @@ find_methods (struct type *t, char *name + } + + static int ++add_minsym_members_compar (const void *ap, const void *bp) ++{ ++ const char *a = *(const char **) ap; ++ const char *b = *(const char **) bp; ++ ++ return strcmp (a, b); ++} ++ ++static int + add_minsym_members (const char *class_name, + const char *member_name, + struct minimal_symbol **msym_arr) +@@ -293,6 +302,7 @@ add_minsym_members (const char *class_na + int i; + int comp_len; + int counter = 0; ++ int src_i, dst_i; + + /* To find the member, we first cheat and use symbol completion. + This will give us a list of all the member names including +@@ -307,6 +317,28 @@ add_minsym_members (const char *class_na + strcat (completion_name, "("); + list = make_symbol_completion_list (completion_name, + completion_name+1); ++ if (list == NULL || list[0] == NULL) ++ { ++ xfree (completion_name); ++ return 0; ++ } ++ ++ /* Make the list entries unique - Multi-PC breakpoints are already resolved ++ by GDB-6.8+. */ ++ counter = 0; ++ while (list && list[counter] != NULL) ++ counter++; ++ qsort (list, counter, sizeof (*list), add_minsym_members_compar); ++ src_i = dst_i = 0; ++ while (src_i + 1 < counter) ++ { ++ if (strcmp (list[src_i], list[src_i + 1]) != 0) ++ list[dst_i++] = list[src_i]; ++ src_i++; ++ } ++ list[dst_i++] = list[src_i++]; ++ gdb_assert (list[src_i] == NULL); ++ list[dst_i] = 0; + + /* Now that we have the list, we generate an array of their + corresponding minimal symbols. */ +@@ -319,6 +351,8 @@ add_minsym_members (const char *class_na + + xfree (list); + ++#if 0 /* Multi-PC breakpoints are already resolved by GDB-6.8+. */ ++ + /* In the case of constructors, there may be in-charge vs not-in-charge + constructors. Check for names with $base which indicates not-in-charge + constructors. */ +@@ -353,6 +387,8 @@ add_minsym_members (const char *class_na + } + xfree (list); + ++#endif /* Multi-PC breakpoints are already resolved by GDB-6.8+. */ ++ + xfree (completion_name); + + return counter; diff --git a/gdb-6.8-fortran-tag-constant.patch b/gdb-6.8-fortran-tag-constant.patch new file mode 100644 index 0000000..5140d25 --- /dev/null +++ b/gdb-6.8-fortran-tag-constant.patch @@ -0,0 +1,76 @@ +Index: gdb-6.8.50.20090228/gdb/dwarf2read.c +=================================================================== +--- gdb-6.8.50.20090228.orig/gdb/dwarf2read.c 2009-03-02 01:07:36.000000000 +0100 ++++ gdb-6.8.50.20090228/gdb/dwarf2read.c 2009-03-02 01:07:50.000000000 +0100 +@@ -1996,6 +1996,7 @@ scan_partial_symbols (struct partial_die + add_partial_subprogram (pdi, lowpc, highpc, need_pc, cu); + break; + case DW_TAG_variable: ++ case DW_TAG_constant: + case DW_TAG_typedef: + case DW_TAG_union_type: + if (!pdi->is_declaration) +@@ -2211,6 +2212,7 @@ add_partial_symbol (struct partial_die_i + } + break; + case DW_TAG_variable: ++ case DW_TAG_constant: + if (pdi->is_external) + { + /* Global Variable. +@@ -4213,7 +4215,8 @@ dwarf2_add_field (struct field_info *fip + fip->non_public_fields = 1; + } + } +- else if (die->tag == DW_TAG_member || die->tag == DW_TAG_variable) ++ else if (die->tag == DW_TAG_member || die->tag == DW_TAG_variable ++ || die->tag == DW_TAG_constant) + { + /* C++ static member. */ + +@@ -4703,7 +4706,8 @@ read_structure_type (struct die_info *di + while (child_die && child_die->tag) + { + if (child_die->tag == DW_TAG_member +- || child_die->tag == DW_TAG_variable) ++ || child_die->tag == DW_TAG_variable ++ || child_die->tag == DW_TAG_constant) + { + /* NOTE: carlton/2002-11-05: A C++ static data member + should be a DW_TAG_member that is a declaration, but +@@ -4822,6 +4826,7 @@ process_structure_scope (struct die_info + { + if (child_die->tag == DW_TAG_member + || child_die->tag == DW_TAG_variable ++ || child_die->tag == DW_TAG_constant + || child_die->tag == DW_TAG_inheritance) + { + /* Do nothing. */ +@@ -6455,6 +6460,7 @@ load_partial_dies (bfd *abfd, gdb_byte * + && abbrev->tag != DW_TAG_subprogram + && abbrev->tag != DW_TAG_lexical_block + && abbrev->tag != DW_TAG_variable ++ && abbrev->tag != DW_TAG_constant + && abbrev->tag != DW_TAG_namespace + && abbrev->tag != DW_TAG_member) + { +@@ -6562,6 +6568,7 @@ load_partial_dies (bfd *abfd, gdb_byte * + if (load_all + || abbrev->tag == DW_TAG_subprogram + || abbrev->tag == DW_TAG_variable ++ || abbrev->tag == DW_TAG_constant + || abbrev->tag == DW_TAG_namespace + || part_die->is_declaration) + { +@@ -8341,6 +8348,11 @@ new_symbol (struct die_info *die, struct + /* Do not add the symbol to any lists. It will be found via + BLOCK_FUNCTION from the blockvector. */ + break; ++ case DW_TAG_constant: ++ SYMBOL_TYPE (sym) = make_cv_type (1, ++ TYPE_VOLATILE (SYMBOL_TYPE (sym)), ++ SYMBOL_TYPE (sym), NULL); ++ /* PASSTHRU */ + case DW_TAG_variable: + /* Compilation with minimal debug info may result in variables + with missing type entries. Change the misleading `void' type diff --git a/gdb-6.8-gcc35998-ada-memory-trash.patch b/gdb-6.8-gcc35998-ada-memory-trash.patch new file mode 100644 index 0000000..1142cc9 --- /dev/null +++ b/gdb-6.8-gcc35998-ada-memory-trash.patch @@ -0,0 +1,18 @@ +--- ./gdb/dwarf2read.c 4 May 2008 17:27:01 -0000 1.260 ++++ ./gdb/dwarf2read.c 4 May 2008 18:26:20 -0000 +@@ -6754,7 +6754,14 @@ dwarf2_attr (struct die_info *die, unsig + for (i = 0; i < die->num_attrs; ++i) + { + if (die->attrs[i].name == name) +- return &die->attrs[i]; ++ { ++ /* GCC PR ada/35998 workaround. */ ++ if (name == DW_AT_byte_size ++ && DW_UNSND (&die->attrs[i]) == 0xffffffff) ++ return NULL; ++ ++ return &die->attrs[i]; ++ } + if (die->attrs[i].name == DW_AT_specification + || die->attrs[i].name == DW_AT_abstract_origin) + spec = &die->attrs[i]; diff --git a/gdb-6.8-glibc-headers-compat.patch b/gdb-6.8-glibc-headers-compat.patch new file mode 100644 index 0000000..39b3b31 --- /dev/null +++ b/gdb-6.8-glibc-headers-compat.patch @@ -0,0 +1,14 @@ +../../libiberty/strsignal.c:552: error: conflicting types for 'psignal' +/usr/include/signal.h:141: error: previous declaration of 'psignal' was here + +--- gdb-6.8/libiberty/strsignal.c-orig 2007-01-31 00:13:04.000000000 +0100 ++++ gdb-6.8/libiberty/strsignal.c 2008-06-17 16:30:13.000000000 +0200 +@@ -549,7 +549,7 @@ followed by a newline. + #ifndef HAVE_PSIGNAL + + void +-psignal (int signo, char *message) ++psignal (int signo, const char *message) + { + if (signal_names == NULL) + { diff --git a/gdb-6.8-inlining-addon.patch b/gdb-6.8-inlining-addon.patch new file mode 100644 index 0000000..211b4f4 --- /dev/null +++ b/gdb-6.8-inlining-addon.patch @@ -0,0 +1,713 @@ +infcall.c : +Revert the change of: gdb-6.8-inlining.patch +causing: FAIL: gdb.base/unwindonsignal.exp: unwindonsignal, stack unwound + +resume() -> target_resume() move of clear_inline_frame_state() is for: +gdb.mi/mi-nsmoribund.exp + +Index: gdb-6.8.50.20090302/gdb/testsuite/gdb.opt/inline-bt.c +=================================================================== +--- gdb-6.8.50.20090302.orig/gdb/testsuite/gdb.opt/inline-bt.c 2009-03-06 19:07:30.000000000 +0100 ++++ gdb-6.8.50.20090302/gdb/testsuite/gdb.opt/inline-bt.c 2009-03-06 19:07:30.000000000 +0100 +@@ -13,10 +13,16 @@ + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +-int x, y; ++/* VOLATILE forces all the inlining to happen as otherwise the whole program ++ gets optimized by CSE to just simple assignments of the results. */ ++volatile int x, y; + volatile int result; + +-void bar(void); ++inline void bar(void) ++{ ++ x += y; /* set breakpoint 1 here */ ++} ++ + + inline int func1(void) + { +Index: gdb-6.8.50.20090302/gdb/testsuite/gdb.opt/inline-bt.exp +=================================================================== +--- gdb-6.8.50.20090302.orig/gdb/testsuite/gdb.opt/inline-bt.exp 2009-03-06 19:07:30.000000000 +0100 ++++ gdb-6.8.50.20090302/gdb/testsuite/gdb.opt/inline-bt.exp 2009-03-06 19:07:30.000000000 +0100 +@@ -41,18 +41,19 @@ if { [skip_inline_frame_tests] } { + return + } + +-set line1 [gdb_get_line_number "set breakpoint 1 here" ${fullsrcfile2}] +-gdb_breakpoint $srcfile2:$line1 ++set line1 [gdb_get_line_number "set breakpoint 1 here" ${srcfile}] ++gdb_breakpoint $srcfile:$line1 + + gdb_test "continue" ".*set breakpoint 1 here.*" "continue to bar (1)" + gdb_test "backtrace" "#0 bar.*#1 .*main.*" "backtrace from bar (1)" +-gdb_test "info frame" ".*called by frame.*" "bar not inlined" ++gdb_test "info frame" ".*inlined into frame.*" "bar inlined" + +-gdb_test "continue" ".*set breakpoint 1 here.*" "continue to bar (2)" +-gdb_test "backtrace" "#0 bar.*#1 .*func1.*#2 .*main.*" \ +- "backtrace from bar (2)" +-gdb_test "up" "#1 .*func1.*" "up from bar (2)" +-gdb_test "info frame" ".*inlined into frame.*" "func1 inlined (2)" ++# gcc-4.3.1 omits the line number information for (2). ++#gdb_test "continue" ".*set breakpoint 1 here.*" "continue to bar (2)" ++#gdb_test "backtrace" "#0 bar.*#1 .*func1.*#2 .*main.*" \ ++# "backtrace from bar (2)" ++#gdb_test "up" "#1 .*func1.*" "up from bar (2)" ++#gdb_test "info frame" ".*inlined into frame.*" "func1 inlined (2)" + + gdb_test "continue" ".*set breakpoint 1 here.*" "continue to bar (3)" + gdb_test "backtrace" "#0 bar.*#1 .*func1.*#2 .*func2.*#3 .*main.*" \ +Index: gdb-6.8.50.20090302/gdb/testsuite/gdb.opt/inline-cmds.c +=================================================================== +--- gdb-6.8.50.20090302.orig/gdb/testsuite/gdb.opt/inline-cmds.c 2009-03-06 19:07:30.000000000 +0100 ++++ gdb-6.8.50.20090302/gdb/testsuite/gdb.opt/inline-cmds.c 2009-03-06 19:07:30.000000000 +0100 +@@ -13,13 +13,19 @@ + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +-int x, y; ++/* VOLATILE forces all the inlining to happen as otherwise the whole program ++ gets optimized by CSE to just simple assignments of the results. */ ++volatile int x, y; + volatile int result; + +-void bar(void); + void marker(void); + void noinline(void); + ++inline void bar(void) ++{ ++ x += y; /* set breakpoint 1 here */ ++} ++ + inline int func1(void) + { + bar (); +Index: gdb-6.8.50.20090302/gdb/testsuite/gdb.opt/inline-cmds.exp +=================================================================== +--- gdb-6.8.50.20090302.orig/gdb/testsuite/gdb.opt/inline-cmds.exp 2009-03-06 19:07:30.000000000 +0100 ++++ gdb-6.8.50.20090302/gdb/testsuite/gdb.opt/inline-cmds.exp 2009-03-06 19:07:30.000000000 +0100 +@@ -45,28 +45,28 @@ if { [skip_inline_frame_tests] } { + + # First, check that the things we expected to be inlined really were, + # and those that shouldn't be weren't. +-set line1 [gdb_get_line_number "set breakpoint 1 here" ${fullsrcfile2}] ++set line1 [gdb_get_line_number "set breakpoint 1 here" ${srcfile2}] + gdb_breakpoint $srcfile2:$line1 +-set line2 [gdb_get_line_number "set breakpoint 2 here" ${fullsrcfile2}] ++set line2 [gdb_get_line_number "set breakpoint 2 here" ${srcfile2}] + gdb_breakpoint $srcfile2:$line2 + +-gdb_test "continue" ".*set breakpoint 1 here.*" "continue to bar (1)" ++gdb_test "continue" "set breakpoint 1 here.*" "continue to bar (1)" + gdb_test "backtrace" "#0 bar.*#1 .*func1.*#2 .*main.*" \ + "backtrace from bar (1)" + gdb_test "up" "#1 .*func1.*" "up from bar (1)" +-gdb_test "info frame" ".*inlined into frame.*" "func1 inlined (1)" ++gdb_test "info frame" "inlined into frame.*" "func1 inlined (1)" + +-gdb_test "continue" ".*set breakpoint 1 here.*" "continue to bar (2)" ++gdb_test "continue" "set breakpoint 1 here.*" "continue to bar (2)" + gdb_test "backtrace" "#0 bar.*#1 .*func1.*#2 .*func2.*#3 .*main.*" \ + "backtrace from bar (2)" + gdb_test "up" "#1 .*func1.*" "up from bar (2)" +-gdb_test "info frame" ".*inlined into frame.*" "func1 inlined (2)" ++gdb_test "info frame" "inlined into frame.*" "func1 inlined (2)" + gdb_test "up" "#2 .*func2.*" "up from func1 (2)" +-gdb_test "info frame" ".*inlined into frame.*" "func2 inlined (2)" ++gdb_test "info frame" "inlined into frame.*" "func2 inlined (2)" + +-gdb_test "continue" ".*set breakpoint 2 here.*" "continue to marker" ++gdb_test "continue" "set breakpoint 2 here.*" "continue to marker" + gdb_test "backtrace" "#0 marker.*#1 .*main.*" "backtrace from marker" +-gdb_test "info frame" ".*called by frame.*" "marker not inlined" ++gdb_test "info frame" "\n called by frame.*" "marker not inlined" + + # Next, check that we can next over inlined functions. We should not end up + # inside any of them. +@@ -201,7 +201,7 @@ set line3 [gdb_get_line_number "set brea + gdb_breakpoint $line3 + gdb_continue_to_breakpoint "consecutive func1" + +-gdb_test "next" ".*func1 .*first call.*" "next to first func1" ++gdb_test "next" "func1 .*first call.*" "next to first func1" + set msg "next to second func1" + gdb_test_multiple "next" $msg { + -re ".*func1 .*second call.*$gdb_prompt $" { +@@ -224,16 +224,16 @@ set line4 [gdb_get_line_number "set brea + gdb_breakpoint $line4 + gdb_continue_to_breakpoint "func1 then func3" + +-gdb_test "next" ".*func1 \\\(\\\);" "next to func1 before func3" +-gdb_test "next" ".*func3 \\\(\\\);" "next to func3" ++gdb_test "next" "func1 \\\(\\\);" "next to func1 before func3" ++gdb_test "next" "func3 \\\(\\\);" "next to func3" + + # Test finishing out of one thing and into another. + set line5 [gdb_get_line_number "set breakpoint 5 here"] + gdb_breakpoint $line5 + gdb_continue_to_breakpoint "finish into func1" + +-gdb_test "next" ".*marker \\\(\\\);" "next to finish marker" +-gdb_test "step" ".*set breakpoint 2 here.*" "step into finish marker" ++gdb_test "next" "marker \\\(\\\);" "next to finish marker" ++gdb_test "step" "set breakpoint 2 here.*" "step into finish marker" + gdb_test "finish" "func1 \\\(\\\);" "finish from marker to func1" + + gdb_test "step" "bar \\\(\\\);" "step into func1 for finish" +@@ -268,12 +268,12 @@ gdb_test "step" "noinline \\\(\\\) at .* + gdb_test "bt" "#0 noinline.*#1 .*outer_inline1.*#2 .*outer_inline2.*#3 main.*" "backtrace at noinline from outer_inline1" + gdb_test "step" "inlined_fn \\\(\\\) at .*" "enter inlined_fn from noinline" + gdb_test "bt" "#0 inlined_fn.*#1 noinline.*#2 .*outer_inline1.*#3 .*outer_inline2.*#4 main.*" "backtrace at inlined_fn from noinline" +-gdb_test "info frame" ".*inlined into frame.*" "inlined_fn from noinline inlined" +-gdb_test "up" "#1 noinline.*" "up to noinline" +-gdb_test "info frame" ".*\n called by frame.*" "noinline from outer_inline1 not inlined" +-gdb_test "up" "#2 .*outer_inline1.*" "up to outer_inline1" +-gdb_test "info frame" ".*inlined into frame.*" "outer_inline1 inlined" +-gdb_test "up" "#3 .*outer_inline2.*" "up to outer_inline2" +-gdb_test "info frame" ".*inlined into frame.*" "outer_inline2 inlined" +-gdb_test "up" "#4 main.*" "up from outer_inline2" +-gdb_test "info frame" ".*\n caller of frame.*" "main not inlined" ++gdb_test "info frame" "inlined into frame.*" "inlined_fn from noinline inlined" ++gdb_test "fini" "" "up to noinline" ++gdb_test "info frame" "\n called by frame.*" "noinline from outer_inline1 not inlined" ++gdb_test "fini" "" "up to outer_inline1" ++gdb_test "info frame" "inlined into frame.*" "outer_inline1 inlined" ++gdb_test "fini" "" "up to outer_inline2" ++gdb_test "info frame" "inlined into frame.*" "outer_inline2 inlined" ++gdb_test "fini" "" "up from outer_inline2" ++gdb_test "info frame" " in main \[^\n\]*\n source language.*" "main not inlined" +Index: gdb-6.8.50.20090302/gdb/testsuite/gdb.opt/inline-locals.c +=================================================================== +--- gdb-6.8.50.20090302.orig/gdb/testsuite/gdb.opt/inline-locals.c 2009-03-06 19:07:30.000000000 +0100 ++++ gdb-6.8.50.20090302/gdb/testsuite/gdb.opt/inline-locals.c 2009-03-06 19:07:30.000000000 +0100 +@@ -13,11 +13,16 @@ + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +-int x, y; ++/* VOLATILE forces all the inlining to happen as otherwise the whole program ++ gets optimized by CSE to just simple assignments of the results. */ ++volatile int x, y; + volatile int result; + volatile int *array_p; + +-void bar(void); ++inline void bar(void) ++{ ++ x += y; /* set breakpoint 1 here */ ++} + + inline int func1(int arg1) + { +Index: gdb-6.8.50.20090302/gdb/testsuite/gdb.opt/inline-locals.exp +=================================================================== +--- gdb-6.8.50.20090302.orig/gdb/testsuite/gdb.opt/inline-locals.exp 2009-03-06 19:07:30.000000000 +0100 ++++ gdb-6.8.50.20090302/gdb/testsuite/gdb.opt/inline-locals.exp 2009-03-06 19:07:30.000000000 +0100 +@@ -43,8 +43,8 @@ if { [skip_inline_var_tests] } { + + set no_frames [skip_inline_frame_tests] + +-set line1 [gdb_get_line_number "set breakpoint 1 here" ${fullsrcfile2}] +-gdb_breakpoint $srcfile2:$line1 ++set line1 [gdb_get_line_number "set breakpoint 1 here" ${srcfile}] ++gdb_breakpoint $srcfile:$line1 + + gdb_test "continue" ".*set breakpoint 1 here.*" "continue to bar (1)" + +@@ -77,6 +77,9 @@ if { ! $no_frames } { + + # Make sure that locals on the stack are found. This is an array to + # prevent it from living in a register. ++if [test_compiler_info "gcc-4-3-*"] { ++ setup_kfail *-*-* "gcc/debug.optimization" ++} + gdb_test "print array\[0\]" "\\\$$decimal = 0" "print local (2)" + + if { ! $no_frames } { +@@ -115,4 +118,7 @@ if { ! $no_frames } { + gdb_test "info locals" ".*arg2 = 184.*" "info locals above bar (3b)" + } + ++if [test_compiler_info "gcc-4-3-*"] { ++ setup_kfail *-*-* "gcc/debug.optimization" ++} + gdb_test "print array\[0\]" "\\\$$decimal = 184" "print local (3)" +Index: gdb-6.8.50.20090302/gdb/frame.c +=================================================================== +--- gdb-6.8.50.20090302.orig/gdb/frame.c 2009-03-06 19:07:30.000000000 +0100 ++++ gdb-6.8.50.20090302/gdb/frame.c 2009-03-06 19:07:30.000000000 +0100 +@@ -269,7 +269,7 @@ fprint_frame (struct ui_file *file, stru + static struct frame_info * + skip_inlined_frames (struct frame_info *frame) + { +- while (get_frame_type (frame) == INLINE_FRAME) ++ while (frame && get_frame_type (frame) == INLINE_FRAME) + frame = get_prev_frame (frame); + + return frame; +@@ -1670,6 +1670,7 @@ get_frame_address_in_block (struct frame + { + /* A draft address. */ + CORE_ADDR pc = get_frame_pc (this_frame); ++ struct thread_info *tp = inferior_thread (); + + struct frame_info *next_frame = this_frame->next; + +@@ -1712,6 +1713,9 @@ get_frame_address_in_block (struct frame + while in an inlined function, then the code address of the + "calling" normal function should not be adjusted either. */ + ++ if (tp->current_pc_is_notcurrent) ++ return pc - 1; ++ + while (get_frame_type (next_frame) == INLINE_FRAME) + next_frame = next_frame->next; + +@@ -1743,7 +1747,7 @@ find_frame_sal (struct frame_info *frame + sym = inline_skipped_symbol (inferior_ptid); + + init_sal (sal); +- if (SYMBOL_LINE (sym) != 0) ++ if (sym != NULL && SYMBOL_LINE (sym) != 0) + { + sal->symtab = SYMBOL_SYMTAB (sym); + sal->line = SYMBOL_LINE (sym); +Index: gdb-6.8.50.20090302/gdb/breakpoint.c +=================================================================== +--- gdb-6.8.50.20090302.orig/gdb/breakpoint.c 2009-03-06 19:07:30.000000000 +0100 ++++ gdb-6.8.50.20090302/gdb/breakpoint.c 2009-03-06 19:07:30.000000000 +0100 +@@ -57,6 +57,7 @@ + #include "top.h" + #include "wrapper.h" + #include "valprint.h" ++#include "inline-frame.h" + + #include "mi/mi-common.h" + +@@ -2902,10 +2903,24 @@ bpstat_check_breakpoint_conditions (bpst + const struct bp_location *bl = bs->breakpoint_at; + struct breakpoint *b = bl->owner; + +- if (frame_id_p (b->frame_id) +- && !frame_id_eq (b->frame_id, get_stack_frame_id (get_current_frame ()))) +- bs->stop = 0; +- else if (bs->stop) ++ if (frame_id_p (b->frame_id)) ++ { ++ struct frame_info *b_frame, *frame; ++ struct frame_id b_frame_id, current_frame_id; ++ ++ b_frame = frame_find_by_id (b->frame_id); ++ ++ /* get_stack_frame_id normalizes the id to the real non-inlined function ++ by skip_inlined_frames. */ ++ b_frame_id = get_stack_frame_id (b_frame); ++ current_frame_id = get_stack_frame_id (get_current_frame ()); ++ ++ /* Completely different (inlining notwithstanding) frames? */ ++ if (!frame_id_eq (b_frame_id, current_frame_id)) ++ bs->stop = 0; ++ } ++ ++ if (bs->stop) + { + int value_is_zero = 0; + +@@ -3044,6 +3059,12 @@ bpstat_stop_status (CORE_ADDR bp_addr, p + bs->print = 0; + } + bs->commands = copy_command_lines (bs->commands); ++ ++ /* Display the innermost inlined frame at a breakpont as it gives to ++ most of the available information. */ ++ if (b->type != bp_until && b->type != bp_finish) ++ while (inline_skipped_frames (ptid)) ++ step_into_inline_frame (ptid); + } + + /* Print nothing for this entry if we dont stop or if we dont print. */ +@@ -5168,9 +5189,9 @@ set_momentary_breakpoint (struct symtab_ + { + struct breakpoint *b; + +- /* If FRAME_ID is valid, it should be a real frame, not an inlined +- one. */ +- gdb_assert (!frame_id_inlined_p (frame_id)); ++ /* We can be returning even into an inline frame. While finish_command will ++ shortcut the case of returning _from_ an inline frame we still may be ++ returning from non-inlined frame _to_ an inlined frame. */ + + b = set_raw_breakpoint (sal, type); + b->enable_state = bp_enabled; +Index: gdb-6.8.50.20090302/gdb/inline-frame.c +=================================================================== +--- gdb-6.8.50.20090302.orig/gdb/inline-frame.c 2009-03-06 19:07:30.000000000 +0100 ++++ gdb-6.8.50.20090302/gdb/inline-frame.c 2009-03-06 19:07:30.000000000 +0100 +@@ -183,6 +183,12 @@ inline_frame_sniffer (const struct frame + if (frame_block == NULL) + return 0; + ++ /* For >=2 inlined functions SKIPPED_SYMBOL needs to be different after each ++ step_into_inline_frame call. But skip_inline_frames is called only once ++ and thus SKIPPED_SYMBOL needs to be calculated by INLINE_FRAME_SNIFFER. */ ++ if (state) ++ state->skipped_symbol = NULL; ++ + /* Calculate DEPTH, the number of inlined functions at this + location. */ + depth = 0; +@@ -192,6 +198,10 @@ inline_frame_sniffer (const struct frame + if (block_inlined_p (cur_block)) + depth++; + ++ if (state && depth == state->skipped_frames ++ && state->skipped_symbol == NULL) ++ state->skipped_symbol = BLOCK_FUNCTION (cur_block); ++ + cur_block = BLOCK_SUPERBLOCK (cur_block); + } + +@@ -275,7 +285,6 @@ skip_inline_frames (ptid_t ptid) + { + CORE_ADDR this_pc; + struct block *frame_block, *cur_block; +- struct symbol *last_sym = NULL; + int skip_count = 0; + struct inline_state *state; + +@@ -296,10 +305,7 @@ skip_inline_frames (ptid_t ptid) + of BLOCK_START. */ + if (BLOCK_START (cur_block) == this_pc + || block_starting_point_at (this_pc, cur_block)) +- { +- skip_count++; +- last_sym = BLOCK_FUNCTION (cur_block); +- } ++ skip_count++; + else + break; + } +@@ -311,7 +317,6 @@ skip_inline_frames (ptid_t ptid) + state = allocate_inline_frame_state (ptid); + state->skipped_frames = skip_count; + state->saved_pc = this_pc; +- state->skipped_symbol = last_sym; + + if (skip_count != 0) + reinit_frame_cache (); +@@ -329,6 +334,23 @@ step_into_inline_frame (ptid_t ptid) + reinit_frame_cache (); + } + ++/* Step out of an inlined function by hiding it. */ ++ ++void ++step_out_of_inline_frame (ptid_t ptid) ++{ ++ struct inline_state *state = find_inline_frame_state (ptid); ++ ++ gdb_assert (state != NULL); ++ ++ /* Simulate the caller adjustment. */ ++ if (state->skipped_frames == 0) ++ state->saved_pc--; ++ ++ state->skipped_frames++; ++ reinit_frame_cache (); ++} ++ + /* Return the number of hidden functions inlined into the current + frame. */ + +Index: gdb-6.8.50.20090302/gdb/testsuite/gdb.opt/inline-markers.c +=================================================================== +--- gdb-6.8.50.20090302.orig/gdb/testsuite/gdb.opt/inline-markers.c 2009-03-06 19:07:30.000000000 +0100 ++++ gdb-6.8.50.20090302/gdb/testsuite/gdb.opt/inline-markers.c 2009-03-06 19:07:30.000000000 +0100 +@@ -15,11 +15,6 @@ + + extern int x, y; + +-void bar(void) +-{ +- x += y; /* set breakpoint 1 here */ +-} +- + void marker(void) + { + x += y; /* set breakpoint 2 here */ +Index: gdb-6.8.50.20090302/gdb/gdbthread.h +=================================================================== +--- gdb-6.8.50.20090302.orig/gdb/gdbthread.h 2009-03-06 19:07:30.000000000 +0100 ++++ gdb-6.8.50.20090302/gdb/gdbthread.h 2009-03-06 19:07:30.000000000 +0100 +@@ -180,6 +180,12 @@ struct thread_info + + /* Private data used by the target vector implementation. */ + struct private_thread_info *private; ++ ++ /* Nonzero if the current frame PC should be unwound as the caller. It is ++ used to keep the backtrace upper levels existing after finish_command into ++ an inlined frame if the current inlined function/block was ending at the ++ current PC. */ ++ int current_pc_is_notcurrent; + }; + + /* Create an empty thread list, or empty the existing one. */ +Index: gdb-6.8.50.20090302/gdb/infcmd.c +=================================================================== +--- gdb-6.8.50.20090302.orig/gdb/infcmd.c 2009-03-06 19:07:30.000000000 +0100 ++++ gdb-6.8.50.20090302/gdb/infcmd.c 2009-03-06 19:07:30.000000000 +0100 +@@ -1391,11 +1391,11 @@ finish_command_continuation (void *arg) + struct type *value_type; + + value_type = TYPE_TARGET_TYPE (SYMBOL_TYPE (a->function)); +- if (!value_type) ++ if (!SYMBOL_INLINED (a->function) && !value_type) + internal_error (__FILE__, __LINE__, + _("finish_command: function has no target type")); + +- if (TYPE_CODE (value_type) != TYPE_CODE_VOID) ++ if (value_type && TYPE_CODE (value_type) != TYPE_CODE_VOID) + print_return_value (SYMBOL_TYPE (a->function), value_type); + } + +@@ -1499,6 +1499,16 @@ finish_forward (struct symbol *function, + + old_chain = make_cleanup_delete_breakpoint (breakpoint); + ++ /* We should _always_ set CURRENT_PC_IS_NOTCURRENT here to always see the ++ calling line with the message `Value returned is ...'. Currently it is ++ seen only if at least one instruction is on that source line after the ++ call instruction. We would also need to hook step_once and only clear ++ CURRENT_PC_IS_NOTCURRENT on the first step. But it would be a change of ++ general non-inlining behavior against upstream. */ ++ ++ if (get_frame_type (frame) == INLINE_FRAME) ++ tp->current_pc_is_notcurrent = 1; ++ + tp->proceed_to_finish = 1; /* We want stop_registers, please... */ + make_cleanup_restore_integer (&suppress_stop_observer); + suppress_stop_observer = 1; +@@ -1522,7 +1532,9 @@ finish_forward (struct symbol *function, + static void + finish_command (char *arg, int from_tty) + { +- struct frame_info *frame; ++ /* FIXME: Rename `current_frame' to `frame' upon a merge. */ ++ struct frame_info *current_frame, *prev_frame; ++ CORE_ADDR frame_pc; + struct symbol *function; + + int async_exec = 0; +@@ -1553,46 +1565,63 @@ finish_command (char *arg, int from_tty) + if (!target_has_execution) + error (_("The program is not running.")); + +- frame = get_prev_frame (get_selected_frame (_("No selected frame."))); +- if (frame == 0) ++ current_frame = get_selected_frame (_("No selected frame.")); ++ frame_pc = get_frame_pc (current_frame); ++ prev_frame = get_prev_frame (current_frame); ++ if (prev_frame == 0) + error (_("\"finish\" not meaningful in the outermost frame.")); + +- clear_proceed_status (); +- + /* Finishing from an inline frame is completely different. We don't + try to show the "return value" - no way to locate it. So we do + not need a completion. */ +- if (get_frame_type (get_selected_frame (_("No selected frame."))) +- == INLINE_FRAME) ++ if (get_frame_type (current_frame) == INLINE_FRAME) + { + struct thread_info *tp = inferior_thread (); +- +- /* Claim we are stepping in the calling frame. An empty step +- range means that we will stop once we aren't in a function +- called by that frame. We don't use the magic "1" value for +- step_range_end, because then infrun will think this is nexti, +- and not step over the rest of this inlined function call. */ + struct symtab_and_line empty_sal; +- init_sal (&empty_sal); +- set_step_info (tp, frame, empty_sal); +- tp->step_range_start = tp->step_range_end = get_frame_pc (frame); +- tp->step_over_calls = STEP_OVER_ALL; ++ struct block *frame_block; + + /* Print info on the selected frame, including level number but not + source. */ + if (from_tty) + { + printf_filtered (_("Run till exit from ")); +- print_stack_frame (get_selected_frame (NULL), 1, LOCATION); ++ print_stack_frame (current_frame, 1, LOCATION); + } + ++ /* Even just a single stepi would get us out of the caller function PC ++ range. */ ++ ++ frame_block = get_frame_block (current_frame, NULL); ++ ++ /* FRAME_BLOCK must be initialized and also the frame printing above must ++ be done still with the original CURRENT_PC_IS_NOTCURRENT setting. */ ++ clear_proceed_status (); ++ ++ if (frame_block && BLOCK_END (frame_block) == frame_pc) ++ { ++ step_out_of_inline_frame (tp->ptid); ++ tp->current_pc_is_notcurrent = 1; ++ normal_stop (); ++ return; ++ } ++ ++ /* Claim we are stepping in the calling frame. An empty step ++ range means that we will stop once we aren't in a function ++ called by that frame. We don't use the magic "1" value for ++ step_range_end, because then infrun will think this is nexti, ++ and not step over the rest of this inlined function call. */ ++ init_sal (&empty_sal); ++ set_step_info (tp, prev_frame, empty_sal); ++ tp->step_range_start = tp->step_range_end = get_frame_pc (prev_frame); ++ tp->step_over_calls = STEP_OVER_ALL; ++ + proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 1); + return; + } + + /* Find the function we will return from. */ + +- function = find_pc_function (get_frame_pc (get_selected_frame (NULL))); ++ function = find_pc_function (frame_pc); + + /* Print info on the selected frame, including level number but not + source. */ +@@ -1606,10 +1635,14 @@ finish_command (char *arg, int from_tty) + print_stack_frame (get_selected_frame (NULL), 1, LOCATION); + } + ++ /* Frames printing above must be done still with the original ++ CURRENT_PC_IS_NOTCURRENT setting. */ ++ clear_proceed_status (); ++ + if (execution_direction == EXEC_REVERSE) + finish_backward (function); + else +- finish_forward (function, frame); ++ finish_forward (function, prev_frame); + } + + +Index: gdb-6.8.50.20090302/gdb/infrun.c +=================================================================== +--- gdb-6.8.50.20090302.orig/gdb/infrun.c 2009-03-06 19:07:30.000000000 +0100 ++++ gdb-6.8.50.20090302/gdb/infrun.c 2009-03-06 19:07:30.000000000 +0100 +@@ -1152,8 +1152,6 @@ a command like `return' or `jump' to con + step = 0; + } + +- clear_inline_frame_state (resume_ptid); +- + if (debug_displaced + && use_displaced_stepping (gdbarch) + && tp->trap_expected) +@@ -1205,6 +1203,8 @@ clear_proceed_status_thread (struct thre + + /* Discard any remaining commands or status from previous stop. */ + bpstat_clear (&tp->stop_bpstat); ++ ++ tp->current_pc_is_notcurrent = 0; + } + + static int +Index: gdb-6.8.50.20090302/gdb/target.c +=================================================================== +--- gdb-6.8.50.20090302.orig/gdb/target.c 2009-03-06 19:07:26.000000000 +0100 ++++ gdb-6.8.50.20090302/gdb/target.c 2009-03-06 19:07:30.000000000 +0100 +@@ -41,6 +41,7 @@ + #include "target-descriptions.h" + #include "gdbthread.h" + #include "solib.h" ++#include "inline-frame.h" + + static void target_info (char *, int); + +@@ -1925,6 +1926,7 @@ target_resume (ptid_t ptid, int step, en + { + struct target_ops *t; + ++ clear_inline_frame_state (ptid); + dcache_invalidate (target_dcache); + + for (t = current_target.beneath; t != NULL; t = t->beneath) +Index: gdb-6.8.50.20090302/gdb/inline-frame.h +=================================================================== +--- gdb-6.8.50.20090302.orig/gdb/inline-frame.h 2009-03-06 19:07:30.000000000 +0100 ++++ gdb-6.8.50.20090302/gdb/inline-frame.h 2009-03-06 19:07:30.000000000 +0100 +@@ -43,6 +43,10 @@ void clear_inline_frame_state (ptid_t pt + + void step_into_inline_frame (ptid_t ptid); + ++/* Step out of an inlined function by hiding it. */ ++ ++void step_out_of_inline_frame (ptid_t ptid); ++ + /* Return the number of hidden functions inlined into the current + frame. */ + +Index: gdb-6.8.50.20090302/gdb/infcall.c +=================================================================== +--- gdb-6.8.50.20090302.orig/gdb/infcall.c 2009-03-06 19:07:30.000000000 +0100 ++++ gdb-6.8.50.20090302/gdb/infcall.c 2009-03-06 19:07:30.000000000 +0100 +@@ -898,8 +898,15 @@ The program being debugged exited while + + if (unwind_on_signal_p) + { +- /* The user wants the context restored. Calling error will +- run inf_status_cleanup, which does all the work. */ ++ /* The user wants the context restored. */ ++ ++ /* We must get back to the frame we were before the ++ dummy call. */ ++ dummy_frame_pop (dummy_id); ++ ++ /* We also need to restore inferior status to that before the ++ dummy call. */ ++ restore_inferior_status (inf_status); + + /* FIXME: Insert a bunch of wrap_here; name can be very + long if it's a C++ name with arguments and stuff. */ +Index: gdb-6.8.50.20090302/gdb/dwarf2read.c +=================================================================== +--- gdb-6.8.50.20090302.orig/gdb/dwarf2read.c 2009-03-06 19:07:30.000000000 +0100 ++++ gdb-6.8.50.20090302/gdb/dwarf2read.c 2009-03-06 19:07:40.000000000 +0100 +@@ -3463,6 +3463,7 @@ read_func_scope (struct die_info *die, s + unsigned die_children = 0; + struct attribute *call_line, *call_file; + int inlined_func = (die->tag == DW_TAG_inlined_subroutine); ++ struct type *type; + + if (inlined_func) + { +@@ -3504,7 +3505,10 @@ read_func_scope (struct die_info *die, s + add_to_cu_func_list (name, lowpc, highpc, cu); + + new = push_context (0, lowpc); +- new->name = new_symbol (die, read_type_die (die, cu), cu); ++ type = read_type_die (die, cu); ++ gdb_assert (type != NULL); ++ new->name = new_symbol (die, type, cu); ++ gdb_assert (TYPE_CODE (SYMBOL_TYPE (new->name)) == TYPE_CODE_FUNC); + + /* If there is a location expression for DW_AT_frame_base, record + it. */ +@@ -8746,6 +8750,7 @@ read_type_die (struct die_info *die, str + break; + case DW_TAG_subprogram: + case DW_TAG_subroutine_type: ++ case DW_TAG_inlined_subroutine: + this_type = read_subroutine_type (die, cu); + break; + case DW_TAG_array_type: diff --git a/gdb-6.8-inlining-by-name.patch b/gdb-6.8-inlining-by-name.patch new file mode 100644 index 0000000..6096247 --- /dev/null +++ b/gdb-6.8-inlining-by-name.patch @@ -0,0 +1,104 @@ +Implement `b ' for with concete inlined instances by +a multiple-PC breakpoint. + +Index: gdb-6.8.50.20081128/gdb/ada-lang.c +=================================================================== +--- gdb-6.8.50.20081128.orig/gdb/ada-lang.c 2008-11-25 00:21:15.000000000 +0100 ++++ gdb-6.8.50.20081128/gdb/ada-lang.c 2008-12-06 21:39:56.000000000 +0100 +@@ -4614,7 +4614,7 @@ remove_irrelevant_renamings (struct ada_ + if (current_block == NULL) + return nsyms; + +- current_function = block_linkage_function (current_block); ++ current_function = block_function (current_block); + if (current_function == NULL) + return nsyms; + +@@ -6625,7 +6625,7 @@ ada_find_renaming_symbol (const char *na + static struct symbol * + find_old_style_renaming_symbol (const char *name, struct block *block) + { +- const struct symbol *function_sym = block_linkage_function (block); ++ const struct symbol *function_sym = block_function (block); + char *rename; + + if (function_sym != NULL) +Index: gdb-6.8.50.20081128/gdb/block.c +=================================================================== +--- gdb-6.8.50.20081128.orig/gdb/block.c 2008-12-06 14:06:16.000000000 +0100 ++++ gdb-6.8.50.20081128/gdb/block.c 2008-12-06 21:40:29.000000000 +0100 +@@ -75,6 +75,19 @@ block_linkage_function (const struct blo + return BLOCK_FUNCTION (bl); + } + ++/* Return the symbol for the function which contains a specified ++ lexical block, described by a struct block BL. Inlined functions ++ can be returned. */ ++ ++struct symbol * ++block_function (const struct block *bl) ++{ ++ while (BLOCK_FUNCTION (bl) == NULL && BLOCK_SUPERBLOCK (bl) != NULL) ++ bl = BLOCK_SUPERBLOCK (bl); ++ ++ return BLOCK_FUNCTION (bl); ++} ++ + /* Return one if BL represents an inlined function. */ + + int +Index: gdb-6.8.50.20081128/gdb/block.h +=================================================================== +--- gdb-6.8.50.20081128.orig/gdb/block.h 2008-12-06 14:06:16.000000000 +0100 ++++ gdb-6.8.50.20081128/gdb/block.h 2008-12-06 21:39:56.000000000 +0100 +@@ -133,6 +133,7 @@ struct blockvector + enum { GLOBAL_BLOCK = 0, STATIC_BLOCK = 1, FIRST_LOCAL_BLOCK = 2 }; + + extern struct symbol *block_linkage_function (const struct block *); ++extern struct symbol *block_function (const struct block *bl); + + extern int block_inlined_p (const struct block *block); + +Index: gdb-6.8.50.20081128/gdb/blockframe.c +=================================================================== +--- gdb-6.8.50.20081128.orig/gdb/blockframe.c 2008-12-06 14:06:16.000000000 +0100 ++++ gdb-6.8.50.20081128/gdb/blockframe.c 2008-12-06 21:39:56.000000000 +0100 +@@ -143,7 +143,7 @@ find_pc_sect_function (CORE_ADDR pc, str + struct block *b = block_for_pc_sect (pc, section); + if (b == 0) + return 0; +- return block_linkage_function (b); ++ return block_function (b); + } + + /* Return the function containing pc value PC. +Index: gdb-6.8.50.20081128/gdb/breakpoint.c +=================================================================== +--- gdb-6.8.50.20081128.orig/gdb/breakpoint.c 2008-12-06 14:06:17.000000000 +0100 ++++ gdb-6.8.50.20081128/gdb/breakpoint.c 2008-12-06 21:39:56.000000000 +0100 +@@ -5712,7 +5712,7 @@ resolve_sal_pc (struct symtab_and_line * + bv = blockvector_for_pc_sect (sal->pc, 0, &b, sal->symtab); + if (bv != NULL) + { +- sym = block_linkage_function (b); ++ sym = block_function (b); + if (sym != NULL) + { + fixup_symbol_section (sym, sal->symtab->objfile); +Index: gdb-6.8.50.20081128/gdb/testsuite/gdb.opt/inline-cmds.exp +=================================================================== +--- gdb-6.8.50.20081128.orig/gdb/testsuite/gdb.opt/inline-cmds.exp 2008-12-06 21:37:27.000000000 +0100 ++++ gdb-6.8.50.20081128/gdb/testsuite/gdb.opt/inline-cmds.exp 2008-12-06 21:41:37.000000000 +0100 +@@ -45,8 +45,10 @@ if { [skip_inline_frame_tests] } { + + # First, check that the things we expected to be inlined really were, + # and those that shouldn't be weren't. +-set line1 [gdb_get_line_number "set breakpoint 1 here" ${srcfile2}] +-gdb_breakpoint $srcfile2:$line1 ++# We test also inlining by the function name, otherwise we would use: ++# set line1 [gdb_get_line_number "set breakpoint 1 here" ${srcfile2}] ++# gdb_breakpoint $srcfile2:$line1 ++gdb_breakpoint "bar" + set line2 [gdb_get_line_number "set breakpoint 2 here" ${srcfile2}] + gdb_breakpoint $srcfile2:$line2 + diff --git a/gdb-6.8-inlining.patch b/gdb-6.8-inlining.patch new file mode 100644 index 0000000..2e688ef --- /dev/null +++ b/gdb-6.8-inlining.patch @@ -0,0 +1,3268 @@ +http://sourceware.org/ml/gdb-patches/2008-07/msg00442.html +with pre-applied and post-unapplied (the patch is currently 2008-12-06 not +applied upstream) +http://sourceware.org/ml/gdb-patches/2008-07/msg00317.html + +Removed dwarf_expr_frame_base NULL check duplicity with *-vla.patch. + +Index: gdb-6.8.50.20090228/gdb/NEWS +=================================================================== +--- gdb-6.8.50.20090228.orig/gdb/NEWS 2009-03-02 01:01:15.000000000 +0100 ++++ gdb-6.8.50.20090228/gdb/NEWS 2009-03-02 01:04:45.000000000 +0100 +@@ -1,6 +1,11 @@ + What has changed in GDB? + (Organized release by release) + ++*** Fedora changes ++ ++* Inlined functions are now supported. They show up in backtraces, and ++the "step", "next", and "finish" commands handle them automatically. ++ + *** Changes since GDB 6.8 + + * GDB now has support for multi-byte and wide character sets on the +Index: gdb-6.8.50.20090228/gdb/block.c +=================================================================== +--- gdb-6.8.50.20090228.orig/gdb/block.c 2009-03-02 01:01:15.000000000 +0100 ++++ gdb-6.8.50.20090228/gdb/block.c 2009-03-02 01:04:45.000000000 +0100 +@@ -47,8 +47,16 @@ contained_in (const struct block *a, con + { + if (!a || !b) + return 0; +- return BLOCK_START (a) >= BLOCK_START (b) +- && BLOCK_END (a) <= BLOCK_END (b); ++ ++ do ++ { ++ if (a == b) ++ return 1; ++ a = BLOCK_SUPERBLOCK (a); ++ } ++ while (a != NULL); ++ ++ return 0; + } + + +@@ -60,12 +68,21 @@ contained_in (const struct block *a, con + struct symbol * + block_linkage_function (const struct block *bl) + { +- while (BLOCK_FUNCTION (bl) == 0 && BLOCK_SUPERBLOCK (bl) != 0) ++ while ((BLOCK_FUNCTION (bl) == NULL || block_inlined_p (bl)) ++ && BLOCK_SUPERBLOCK (bl) != NULL) + bl = BLOCK_SUPERBLOCK (bl); + + return BLOCK_FUNCTION (bl); + } + ++/* Return one if BL represents an inlined function. */ ++ ++int ++block_inlined_p (const struct block *bl) ++{ ++ return BLOCK_FUNCTION (bl) != NULL && SYMBOL_INLINED (BLOCK_FUNCTION (bl)); ++} ++ + /* Return the blockvector immediately containing the innermost lexical + block containing the specified pc value and section, or 0 if there + is none. PBLOCK is a pointer to the block. If PBLOCK is NULL, we +Index: gdb-6.8.50.20090228/gdb/block.h +=================================================================== +--- gdb-6.8.50.20090228.orig/gdb/block.h 2009-01-03 06:57:50.000000000 +0100 ++++ gdb-6.8.50.20090228/gdb/block.h 2009-03-02 01:04:45.000000000 +0100 +@@ -65,7 +65,7 @@ struct block + CORE_ADDR endaddr; + + /* The symbol that names this block, if the block is the body of a +- function; otherwise, zero. */ ++ function (real or inlined); otherwise, zero. */ + + struct symbol *function; + +@@ -134,6 +134,8 @@ enum { GLOBAL_BLOCK = 0, STATIC_BLOCK = + + extern struct symbol *block_linkage_function (const struct block *); + ++extern int block_inlined_p (const struct block *block); ++ + extern int contained_in (const struct block *, const struct block *); + + extern struct blockvector *blockvector_for_pc (CORE_ADDR, struct block **); +Index: gdb-6.8.50.20090228/gdb/blockframe.c +=================================================================== +--- gdb-6.8.50.20090228.orig/gdb/blockframe.c 2009-01-03 06:57:50.000000000 +0100 ++++ gdb-6.8.50.20090228/gdb/blockframe.c 2009-03-02 01:04:45.000000000 +0100 +@@ -36,6 +36,7 @@ + #include "command.h" + #include "gdbcmd.h" + #include "block.h" ++#include "inline-frame.h" + + /* Prototypes for exported functions. */ + +@@ -61,11 +62,29 @@ struct block * + get_frame_block (struct frame_info *frame, CORE_ADDR *addr_in_block) + { + const CORE_ADDR pc = get_frame_address_in_block (frame); ++ struct frame_info *next_frame; ++ struct block *bl; ++ int inline_count; + + if (addr_in_block) + *addr_in_block = pc; + +- return block_for_pc (pc); ++ bl = block_for_pc (pc); ++ if (bl == NULL) ++ return NULL; ++ ++ inline_count = frame_inlined_callees (frame); ++ ++ while (inline_count > 0) ++ { ++ if (block_inlined_p (bl)) ++ inline_count--; ++ ++ bl = BLOCK_SUPERBLOCK (bl); ++ gdb_assert (bl != NULL); ++ } ++ ++ return bl; + } + + CORE_ADDR +@@ -104,9 +123,14 @@ struct symbol * + get_frame_function (struct frame_info *frame) + { + struct block *bl = get_frame_block (frame, 0); +- if (bl == 0) +- return 0; +- return block_linkage_function (bl); ++ ++ if (bl == NULL) ++ return NULL; ++ ++ while (BLOCK_FUNCTION (bl) == NULL && BLOCK_SUPERBLOCK (bl) != NULL) ++ bl = BLOCK_SUPERBLOCK (bl); ++ ++ return BLOCK_FUNCTION (bl); + } + + +@@ -350,8 +374,8 @@ block_innermost_frame (struct block *blo + frame = get_current_frame (); + while (frame != NULL) + { +- calling_pc = get_frame_address_in_block (frame); +- if (calling_pc >= start && calling_pc < end) ++ struct block *frame_block = get_frame_block (frame, NULL); ++ if (frame_block != NULL && contained_in (frame_block, block)) + return frame; + + frame = get_prev_frame (frame); +Index: gdb-6.8.50.20090228/gdb/breakpoint.c +=================================================================== +--- gdb-6.8.50.20090228.orig/gdb/breakpoint.c 2009-03-02 01:04:33.000000000 +0100 ++++ gdb-6.8.50.20090228/gdb/breakpoint.c 2009-03-02 01:04:45.000000000 +0100 +@@ -2641,19 +2641,21 @@ watchpoint_check (void *p) + within_current_scope = 1; + else + { +- /* There is no current frame at this moment. If we're going to have +- any chance of handling watchpoints on local variables, we'll need +- the frame chain (so we can determine if we're in scope). */ +- reinit_frame_cache (); + fr = frame_find_by_id (b->watchpoint_frame); + within_current_scope = (fr != NULL); + + /* If we've gotten confused in the unwinder, we might have + returned a frame that can't describe this variable. */ +- if (within_current_scope +- && (block_linkage_function (b->exp_valid_block) +- != get_frame_function (fr))) +- within_current_scope = 0; ++ if (within_current_scope) ++ { ++ struct symbol *function; ++ ++ function = get_frame_function (fr); ++ if (function == NULL ++ || !contained_in (b->exp_valid_block, ++ SYMBOL_BLOCK_VALUE (function))) ++ within_current_scope = 0; ++ } + + /* in_function_epilogue_p() returns a non-zero value if we're still + in the function but the stack frame has already been invalidated. +@@ -2665,10 +2667,9 @@ watchpoint_check (void *p) + that the watchpoint frame couldn't be found by frame_find_by_id() + because the current PC is currently in an epilogue. Calling + gdbarch_in_function_epilogue_p() also when fr == NULL fixes that. */ +- if ((!within_current_scope || fr == get_current_frame ()) +- && gdbarch_in_function_epilogue_p (current_gdbarch, read_pc ())) ++ if (gdbarch_in_function_epilogue_p (current_gdbarch, read_pc ())) + return WP_VALUE_NOT_CHANGED; +- if (fr && within_current_scope) ++ if (within_current_scope) + /* If we end up stopping, the current frame will get selected + in normal_stop. So this call to select_frame won't affect + the user. */ +@@ -2902,7 +2903,7 @@ bpstat_check_breakpoint_conditions (bpst + struct breakpoint *b = bl->owner; + + if (frame_id_p (b->frame_id) +- && !frame_id_eq (b->frame_id, get_frame_id (get_current_frame ()))) ++ && !frame_id_eq (b->frame_id, get_stack_frame_id (get_current_frame ()))) + bs->stop = 0; + else if (bs->stop) + { +@@ -2917,8 +2918,12 @@ bpstat_check_breakpoint_conditions (bpst + + if (bl->cond && bl->owner->disposition != disp_del_at_next_stop) + { +- /* Need to select the frame, with all that implies +- so that the conditions will have the right context. */ ++ /* Need to select the frame, with all that implies so that ++ the conditions will have the right context. Because we ++ use the frame, we will not see an inlined function's ++ variables when we arrive at a breakpoint at the start ++ of the inlined function; the current frame will be the ++ call site. */ + select_frame (get_current_frame ()); + value_is_zero + = catch_errors (breakpoint_cond_eval, (bl->cond), +@@ -5162,6 +5167,11 @@ set_momentary_breakpoint (struct symtab_ + enum bptype type) + { + struct breakpoint *b; ++ ++ /* If FRAME_ID is valid, it should be a real frame, not an inlined ++ one. */ ++ gdb_assert (!frame_id_inlined_p (frame_id)); ++ + b = set_raw_breakpoint (sal, type); + b->enable_state = bp_enabled; + b->disposition = disp_donttouch; +@@ -6175,7 +6185,6 @@ watch_command_1 (char *arg, int accessfl + struct block *exp_valid_block; + struct value *val, *mark, *val_chain; + struct frame_info *frame; +- struct frame_info *prev_frame = NULL; + char *exp_start = NULL; + char *exp_end = NULL; + char *tok, *id_tok_start, *end_tok; +@@ -6336,34 +6345,34 @@ watch_command_1 (char *arg, int accessfl + bp_type = bp_watchpoint; + + frame = block_innermost_frame (exp_valid_block); +- if (frame) +- prev_frame = get_prev_frame (frame); +- else +- prev_frame = NULL; + + /* If the expression is "local", then set up a "watchpoint scope" + breakpoint at the point where we've left the scope of the watchpoint + expression. Create the scope breakpoint before the watchpoint, so + that we will encounter it first in bpstat_stop_status. */ +- if (innermost_block && prev_frame) ++ if (innermost_block && frame) + { +- scope_breakpoint = create_internal_breakpoint (get_frame_pc (prev_frame), +- bp_watchpoint_scope); ++ if (frame_id_p (frame_unwind_id (frame))) ++ { ++ scope_breakpoint ++ = create_internal_breakpoint (frame_pc_unwind (frame), ++ bp_watchpoint_scope); + +- scope_breakpoint->enable_state = bp_enabled; ++ scope_breakpoint->enable_state = bp_enabled; + +- /* Automatically delete the breakpoint when it hits. */ +- scope_breakpoint->disposition = disp_del; ++ /* Automatically delete the breakpoint when it hits. */ ++ scope_breakpoint->disposition = disp_del; + +- /* Only break in the proper frame (help with recursion). */ +- scope_breakpoint->frame_id = get_frame_id (prev_frame); ++ /* Only break in the proper frame (help with recursion). */ ++ scope_breakpoint->frame_id = frame_unwind_id (frame); + +- /* Set the address at which we will stop. */ +- scope_breakpoint->loc->requested_address +- = get_frame_pc (prev_frame); +- scope_breakpoint->loc->address +- = adjust_breakpoint_address (scope_breakpoint->loc->requested_address, +- scope_breakpoint->type); ++ /* Set the address at which we will stop. */ ++ scope_breakpoint->loc->requested_address ++ = frame_pc_unwind (frame); ++ scope_breakpoint->loc->address ++ = adjust_breakpoint_address (scope_breakpoint->loc->requested_address, ++ scope_breakpoint->type); ++ } + } + + /* Now set up the breakpoint. */ +@@ -6544,7 +6553,6 @@ until_break_command (char *arg, int from + struct symtabs_and_lines sals; + struct symtab_and_line sal; + struct frame_info *frame = get_selected_frame (NULL); +- struct frame_info *prev_frame = get_prev_frame (frame); + struct breakpoint *breakpoint; + struct breakpoint *breakpoint2 = NULL; + struct cleanup *old_chain; +@@ -6577,20 +6585,22 @@ until_break_command (char *arg, int from + we don't specify a frame at which we need to stop. */ + breakpoint = set_momentary_breakpoint (sal, null_frame_id, bp_until); + else +- /* Otherwise, specify the current frame, because we want to stop only ++ /* Otherwise, specify the selected frame, because we want to stop only + at the very same frame. */ +- breakpoint = set_momentary_breakpoint (sal, get_frame_id (frame), ++ breakpoint = set_momentary_breakpoint (sal, get_stack_frame_id (frame), + bp_until); + + old_chain = make_cleanup_delete_breakpoint (breakpoint); + + /* Keep within the current frame, or in frames called by the current + one. */ +- if (prev_frame) ++ ++ if (frame_id_p (frame_unwind_id (frame))) + { +- sal = find_pc_line (get_frame_pc (prev_frame), 0); +- sal.pc = get_frame_pc (prev_frame); +- breakpoint2 = set_momentary_breakpoint (sal, get_frame_id (prev_frame), ++ sal = find_pc_line (frame_pc_unwind (frame), 0); ++ sal.pc = frame_pc_unwind (frame); ++ breakpoint2 = set_momentary_breakpoint (sal, ++ frame_unwind_id (frame), + bp_until); + make_cleanup_delete_breakpoint (breakpoint2); + } +Index: gdb-6.8.50.20090228/gdb/buildsym.c +=================================================================== +--- gdb-6.8.50.20090228.orig/gdb/buildsym.c 2009-03-02 01:01:15.000000000 +0100 ++++ gdb-6.8.50.20090228/gdb/buildsym.c 2009-03-02 01:04:45.000000000 +0100 +@@ -1155,6 +1155,12 @@ end_symtab (CORE_ADDR end_addr, struct o + struct symbol *sym; + struct dict_iterator iter; + ++ /* Inlined functions may have symbols not in the global or static ++ symbol lists. */ ++ if (BLOCK_FUNCTION (block) != NULL) ++ if (SYMBOL_SYMTAB (BLOCK_FUNCTION (block)) == NULL) ++ SYMBOL_SYMTAB (BLOCK_FUNCTION (block)) = symtab; ++ + for (sym = dict_iterator_first (BLOCK_DICT (block), &iter); + sym != NULL; + sym = dict_iterator_next (&iter)) +Index: gdb-6.8.50.20090228/gdb/doc/gdb.texinfo +=================================================================== +--- gdb-6.8.50.20090228.orig/gdb/doc/gdb.texinfo 2009-03-02 01:04:33.000000000 +0100 ++++ gdb-6.8.50.20090228/gdb/doc/gdb.texinfo 2009-03-02 01:04:45.000000000 +0100 +@@ -137,6 +137,7 @@ software in general. We will miss him. + * Stack:: Examining the stack + * Source:: Examining source files + * Data:: Examining data ++* Optimized Code:: Debugging optimized code + * Macros:: Preprocessor Macros + * Tracepoints:: Debugging remote targets non-intrusively + * Overlays:: Debugging programs that use overlays +@@ -1824,7 +1825,7 @@ To request debugging information, specif + the compiler. + + Programs that are to be shipped to your customers are compiled with +-optimizations, using the @samp{-O} compiler option. However, many ++optimizations, using the @samp{-O} compiler option. However, some + compilers are unable to handle the @samp{-g} and @samp{-O} options + together. Using those compilers, you cannot generate optimized + executables containing debugging information. +@@ -1833,22 +1834,7 @@ executables containing debugging informa + without @samp{-O}, making it possible to debug optimized code. We + recommend that you @emph{always} use @samp{-g} whenever you compile a + program. You may think your program is correct, but there is no sense +-in pushing your luck. +- +-@cindex optimized code, debugging +-@cindex debugging optimized code +-When you debug a program compiled with @samp{-g -O}, remember that the +-optimizer is rearranging your code; the debugger shows you what is +-really there. Do not be too surprised when the execution path does not +-exactly match your source file! An extreme example: if you define a +-variable, but never use it, @value{GDBN} never sees that +-variable---because the compiler optimizes it out of existence. +- +-Some things do not work as well with @samp{-g -O} as with just +-@samp{-g}, particularly on machines with instruction scheduling. If in +-doubt, recompile with @samp{-g} alone, and if this fixes the problem, +-please report it to us as a bug (including a test case!). +-@xref{Variables}, for more information about debugging optimized code. ++in pushing your luck. For more information, see @ref{Optimized Code}. + + Older versions of the @sc{gnu} C compiler permitted a variant option + @w{@samp{-gg}} for debugging information. @value{GDBN} no longer supports this +@@ -8393,6 +8379,107 @@ $1 = 1 + $2 = (void *) 0x8049560 + @end smallexample + ++@node Optimized Code ++@chapter Debugging Optimized Code ++@cindex optimized code, debugging ++@cindex debugging optimized code ++ ++Almost all compilers support optimization. With optimization ++disabled, the compiler generates assembly code that corresponds ++directly to your source code, in a simplistic way. As the compiler ++applies more powerful optimizations, the generated assembly code ++diverges from your original source code. With help from debugging ++information generated by the compiler, @value{GDBN} can map from ++the running program back to constructs from your original source. ++ ++@value{GDBN} is more accurate with optimization disabled. If you ++can recompile without optimization, it is easier to follow the ++progress of your program during debugging. But, there are many cases ++where you may need to debug an optimized version. ++ ++When you debug a program compiled with @samp{-g -O}, remember that the ++optimizer has rearranged your code; the debugger shows you what is ++really there. Do not be too surprised when the execution path does not ++exactly match your source file! An extreme example: if you define a ++variable, but never use it, @value{GDBN} never sees that ++variable---because the compiler optimizes it out of existence. ++ ++Some things do not work as well with @samp{-g -O} as with just ++@samp{-g}, particularly on machines with instruction scheduling. If in ++doubt, recompile with @samp{-g} alone, and if this fixes the problem, ++please report it to us as a bug (including a test case!). ++@xref{Variables}, for more information about debugging optimized code. ++ ++@menu ++* Inline Functions:: How @value{GDBN} presents inlining ++@end menu ++ ++@node Inline Functions ++@section Inline Functions ++@cindex inline functions, debugging ++ ++@dfn{Inlining} is an optimization that inserts a copy of the function ++body directly at each call site, instead of jumping to a shared ++routine. @value{GDBN} displays inlined functions just like ++non-inlined functions. They appear in backtraces. You can view their ++arguments and local variables, step into them with @code{step}, skip ++them with @code{next}, and escape from them with @code{finish}. ++You can check whether a function was inlined by using the ++@code{info frame} command. ++ ++For @value{GDBN} to support inlined functions, the compiler must ++record information about inlining in the debug information --- ++@value{NGCC} using the @sc{dwarf 2} format does this, and several ++other compilers do also. @value{GDBN} only supports inlined functions ++when using @sc{dwarf 2}. Versions of @value{NGCC} before 4.1 ++do not emit two required attributes (@samp{DW_AT_call_file} and ++@samp{DW_AT_call_line}); @value{GDBN} does not display inlined ++function calls with earlier versions of @value{NGCC}. It instead ++displays the arguments and local variables of inlined functions as ++local variables in the caller. ++ ++The body of an inlined function is directly included at its call site; ++unlike a non-inlined function, there are no instructions devoted to ++the call. @value{GDBN} still pretends that the call site and the ++start of the inlined function are different instructions. Stepping to ++the call site shows the call site, and then stepping again shows ++the first line of the inlined function, even though no additional ++instructions are executed. ++ ++This makes source-level debugging much clearer; you can see both the ++context of the call and then the effect of the call. Only stepping by ++a single instruction using @code{stepi} or @code{nexti} does not do ++this; single instruction steps always show the inlined body. ++ ++There are some ways that @value{GDBN} does not pretend that inlined ++function calls are the same as normal calls: ++ ++@itemize @bullet ++@item ++You cannot set breakpoints on inlined functions. @value{GDBN} ++either reports that there is no symbol with that name, or else sets the ++breakpoint only on non-inlined copies of the function. This limitation ++will be removed in a future version of @value{GDBN}; until then, ++set a breakpoint by line number on the first line of the inlined ++function instead. ++ ++@item ++Setting breakpoints at the call site of an inlined function may not ++work, because the call site does not contain any code. @value{GDBN} ++may incorrectly move the breakpoint to the next line of the enclosing ++function, after the call. This limitation will be removed in a future ++version of @value{GDBN}; until then, set a breakpoint on an earlier line ++or inside the inlined function instead. ++ ++@item ++@value{GDBN} cannot locate the return value of inlined calls after ++using the @code{finish} command. This is a limitation of compiler-generated ++debugging information; after @code{finish}, you can step to the next line ++and print a variable where your program stored the return value. ++ ++@end itemize ++ ++ + @node Macros + @chapter C Preprocessor Macros + +Index: gdb-6.8.50.20090228/gdb/dwarf2loc.c +=================================================================== +--- gdb-6.8.50.20090228.orig/gdb/dwarf2loc.c 2009-03-02 01:01:15.000000000 +0100 ++++ gdb-6.8.50.20090228/gdb/dwarf2loc.c 2009-03-02 01:04:45.000000000 +0100 +@@ -31,6 +31,7 @@ + #include "regcache.h" + #include "objfiles.h" + #include "exceptions.h" ++#include "block.h" + + #include "elf/dwarf2.h" + #include "dwarf2expr.h" +@@ -150,7 +151,10 @@ dwarf_expr_frame_base (void *baton, gdb_ + struct symbol *framefunc; + struct dwarf_expr_baton *debaton = (struct dwarf_expr_baton *) baton; + +- framefunc = get_frame_function (debaton->frame); ++ /* Use block_linkage_function, which returns a real (not inlined) ++ function, instead of get_frame_function, which may return an ++ inlined function. */ ++ framefunc = block_linkage_function (get_frame_block (debaton->frame, NULL)); + + /* If we found a frame-relative symbol then it was certainly within + some function associated with a frame. If we can't find the frame, +Index: gdb-6.8.50.20090228/gdb/dwarf2read.c +=================================================================== +--- gdb-6.8.50.20090228.orig/gdb/dwarf2read.c 2009-03-02 01:04:32.000000000 +0100 ++++ gdb-6.8.50.20090228/gdb/dwarf2read.c 2009-03-02 01:07:36.000000000 +0100 +@@ -50,6 +50,7 @@ + #include "c-lang.h" + #include "typeprint.h" + #include "top.h" ++#include "block.h" + + #include + #include "gdb_string.h" +@@ -2984,12 +2985,8 @@ process_die (struct die_info *die, struc + read_file_scope (die, cu); + break; + case DW_TAG_subprogram: +- read_func_scope (die, cu); +- break; + case DW_TAG_inlined_subroutine: +- /* FIXME: These are ignored for now. +- They could be used to set breakpoints on all inlined instances +- of a function and make GDB `next' properly over inlined functions. */ ++ read_func_scope (die, cu); + break; + case DW_TAG_lexical_block: + case DW_TAG_try_block: +@@ -3464,6 +3461,22 @@ read_func_scope (struct die_info *die, s + CORE_ADDR baseaddr; + struct block *block; + unsigned die_children = 0; ++ struct attribute *call_line, *call_file; ++ int inlined_func = (die->tag == DW_TAG_inlined_subroutine); ++ ++ if (inlined_func) ++ { ++ /* If we do not have call site information, we can't show the ++ caller of this inlined function. That's too confusing, so ++ only use the scope for local variables. */ ++ call_line = dwarf2_attr (die, DW_AT_call_line, cu); ++ call_file = dwarf2_attr (die, DW_AT_call_file, cu); ++ if (call_line == NULL || call_file == NULL) ++ { ++ read_lexical_block_scope (die, cu); ++ return; ++ } ++ } + + baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); + +@@ -7526,6 +7539,9 @@ die_specification (struct die_info *die, + *spec_cu); + + if (spec_attr == NULL) ++ spec_attr = dwarf2_attr (die, DW_AT_abstract_origin, *spec_cu); ++ ++ if (spec_attr == NULL) + return NULL; + else + return follow_die_ref (die, spec_attr, spec_cu); +@@ -8209,6 +8225,7 @@ new_symbol (struct die_info *die, struct + struct attribute *attr = NULL; + struct attribute *attr2 = NULL; + CORE_ADDR baseaddr; ++ int inlined_func = (die->tag == DW_TAG_inlined_subroutine); + + baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); + +@@ -8259,13 +8276,17 @@ new_symbol (struct die_info *die, struct + SYMBOL_TYPE (sym) = type; + else + SYMBOL_TYPE (sym) = die_type (die, cu); +- attr = dwarf2_attr (die, DW_AT_decl_line, cu); ++ attr = dwarf2_attr (die, ++ inlined_func ? DW_AT_call_line : DW_AT_decl_line, ++ cu); + if (attr) + { + SYMBOL_LINE (sym) = DW_UNSND (attr); + } + +- attr = dwarf2_attr (die, DW_AT_decl_file, cu); ++ attr = dwarf2_attr (die, ++ inlined_func ? DW_AT_call_file : DW_AT_decl_file, ++ cu); + if (attr) + { + int file_index = DW_UNSND (attr); +@@ -8312,6 +8333,14 @@ new_symbol (struct die_info *die, struct + add_symbol_to_list (sym, cu->list_in_scope); + } + break; ++ case DW_TAG_inlined_subroutine: ++ /* SYMBOL_BLOCK_VALUE (sym) will be filled in later by ++ finish_block. */ ++ SYMBOL_CLASS (sym) = LOC_BLOCK; ++ SYMBOL_INLINED (sym) = 1; ++ /* Do not add the symbol to any lists. It will be found via ++ BLOCK_FUNCTION from the blockvector. */ ++ break; + case DW_TAG_variable: + /* Compilation with minimal debug info may result in variables + with missing type entries. Change the misleading `void' type +@@ -8367,7 +8396,14 @@ new_symbol (struct die_info *die, struct + } + break; + case DW_TAG_formal_parameter: +- SYMBOL_IS_ARGUMENT (sym) = 1; ++ /* If we are inside a function, mark this as an argument. If ++ not, we might be looking at an argument to an inlined function ++ when we do not have enough information to show inlined frames; ++ pretend it's a local variable in that case so that the user can ++ still see it. */ ++ if (context_stack_depth > 0 ++ && context_stack[context_stack_depth - 1].name != NULL) ++ SYMBOL_IS_ARGUMENT (sym) = 1; + attr = dwarf2_attr (die, DW_AT_location, cu); + if (attr) + { +Index: gdb-6.8.50.20090228/gdb/frame-unwind.c +=================================================================== +--- gdb-6.8.50.20090228.orig/gdb/frame-unwind.c 2009-01-03 06:57:51.000000000 +0100 ++++ gdb-6.8.50.20090228/gdb/frame-unwind.c 2009-03-02 01:04:45.000000000 +0100 +@@ -21,6 +21,7 @@ + #include "frame.h" + #include "frame-unwind.h" + #include "dummy-frame.h" ++#include "inline-frame.h" + #include "value.h" + #include "regcache.h" + +@@ -51,8 +52,10 @@ frame_unwind_init (struct obstack *obsta + can't override this. */ + table->list = OBSTACK_ZALLOC (obstack, struct frame_unwind_table_entry); + table->list->unwinder = dummy_frame_unwind; ++ table->list->next = OBSTACK_ZALLOC (obstack, struct frame_unwind_table_entry); ++ table->list->next->unwinder = inline_frame_unwind; + /* The insertion point for OSABI sniffers. */ +- table->osabi_head = &table->list->next; ++ table->osabi_head = &table->list->next->next; + return table; + } + +Index: gdb-6.8.50.20090228/gdb/frame.c +=================================================================== +--- gdb-6.8.50.20090228.orig/gdb/frame.c 2009-03-02 01:01:44.000000000 +0100 ++++ gdb-6.8.50.20090228/gdb/frame.c 2009-03-02 01:04:45.000000000 +0100 +@@ -41,8 +41,14 @@ + #include "objfiles.h" + #include "exceptions.h" + #include "gdbthread.h" ++#include "block.h" ++#include "inline-frame.h" + + static struct frame_info *get_prev_frame_1 (struct frame_info *this_frame); ++static struct frame_info *get_prev_frame_raw (struct frame_info *this_frame); ++ ++static void deprecated_update_frame_pc_hack (struct frame_info *frame, ++ CORE_ADDR pc); + + /* We keep a cache of stack frames, each of which is a "struct + frame_info". The innermost one gets allocated (in +@@ -183,6 +189,8 @@ fprint_frame_id (struct ui_file *file, s + fprint_field (file, "code", id.code_addr_p, id.code_addr); + fprintf_unfiltered (file, ","); + fprint_field (file, "special", id.special_addr_p, id.special_addr); ++ if (id.inline_depth) ++ fprintf_unfiltered (file, ",inlined=%d", id.inline_depth); + fprintf_unfiltered (file, "}"); + } + +@@ -197,6 +205,12 @@ fprint_frame_type (struct ui_file *file, + case DUMMY_FRAME: + fprintf_unfiltered (file, "DUMMY_FRAME"); + return; ++ case INLINE_FRAME: ++ fprintf_unfiltered (file, "INLINE_FRAME"); ++ return; ++ case SENTINEL_FRAME: ++ fprintf_unfiltered (file, "SENTINEL_FRAME"); ++ return; + case SIGTRAMP_FRAME: + fprintf_unfiltered (file, "SIGTRAMP_FRAME"); + return; +@@ -249,6 +263,18 @@ fprint_frame (struct ui_file *file, stru + fprintf_unfiltered (file, "}"); + } + ++/* Given FRAME, return the enclosing normal frame for inlined ++ function frames. Otherwise return the original frame. */ ++ ++static struct frame_info * ++skip_inlined_frames (struct frame_info *frame) ++{ ++ while (get_frame_type (frame) == INLINE_FRAME) ++ frame = get_prev_frame (frame); ++ ++ return frame; ++} ++ + /* Return a frame uniq ID that can be used to, later, re-find the + frame. */ + +@@ -281,13 +307,21 @@ get_frame_id (struct frame_info *fi) + } + + struct frame_id ++get_stack_frame_id (struct frame_info *next_frame) ++{ ++ return get_frame_id (skip_inlined_frames (next_frame)); ++} ++ ++struct frame_id + frame_unwind_id (struct frame_info *next_frame) + { + /* Use prev_frame, and not get_prev_frame. The latter will truncate + the frame chain, leading to this function unintentionally + returning a null_frame_id (e.g., when a caller requests the frame + ID of "main()"s caller. */ +- return get_frame_id (get_prev_frame_1 (next_frame)); ++ ++ next_frame = skip_inlined_frames (next_frame); ++ return get_frame_id (skip_inlined_frames (get_prev_frame_1 (next_frame))); + } + + const struct frame_id null_frame_id; /* All zeros. */ +@@ -342,6 +376,15 @@ frame_id_p (struct frame_id l) + } + + int ++frame_id_inlined_p (struct frame_id l) ++{ ++ if (!frame_id_p (l)) ++ return 0; ++ ++ return (l.inline_depth != 0); ++} ++ ++int + frame_id_eq (struct frame_id l, struct frame_id r) + { + int eq; +@@ -352,21 +395,22 @@ frame_id_eq (struct frame_id l, struct f + else if (l.stack_addr != r.stack_addr) + /* If .stack addresses are different, the frames are different. */ + eq = 0; +- else if (!l.code_addr_p || !r.code_addr_p) +- /* An invalid code addr is a wild card, always succeed. */ +- eq = 1; +- else if (l.code_addr != r.code_addr) +- /* If .code addresses are different, the frames are different. */ ++ else if (l.code_addr_p && r.code_addr_p && l.code_addr != r.code_addr) ++ /* An invalid code addr is a wild card. If .code addresses are ++ different, the frames are different. */ + eq = 0; +- else if (!l.special_addr_p || !r.special_addr_p) +- /* An invalid special addr is a wild card (or unused), always succeed. */ +- eq = 1; +- else if (l.special_addr == r.special_addr) ++ else if (l.special_addr_p && r.special_addr_p ++ && l.special_addr != r.special_addr) ++ /* An invalid special addr is a wild card (or unused). Otherwise ++ if special addresses are different, the frames are different. */ ++ eq = 0; ++ else if (l.inline_depth != r.inline_depth) ++ /* If inline depths are different, the frames must be different. */ ++ eq = 0; ++ else + /* Frames are equal. */ + eq = 1; +- else +- /* No luck. */ +- eq = 0; ++ + if (frame_debug) + { + fprintf_unfiltered (gdb_stdlog, "{ frame_id_eq (l="); +@@ -411,6 +455,29 @@ frame_id_inner (struct gdbarch *gdbarch, + if (!l.stack_addr_p || !r.stack_addr_p) + /* Like NaN, any operation involving an invalid ID always fails. */ + inner = 0; ++ else if (l.inline_depth > r.inline_depth ++ && l.stack_addr == r.stack_addr ++ && l.code_addr_p == r.code_addr_p ++ && l.special_addr_p == r.special_addr_p ++ && l.special_addr == r.special_addr) ++ { ++ /* Same function, different inlined functions. */ ++ struct block *lb, *rb; ++ ++ gdb_assert (l.code_addr_p && r.code_addr_p); ++ ++ lb = block_for_pc (l.code_addr); ++ rb = block_for_pc (r.code_addr); ++ ++ if (lb == NULL || rb == NULL) ++ /* Something's gone wrong. */ ++ inner = 0; ++ else ++ /* This will return true if LB and RB are the same block, or ++ if the block with the smaller depth lexically encloses the ++ block with the greater depth. */ ++ inner = contained_in (lb, rb); ++ } + else + /* Only return non-zero when strictly inner than. Note that, per + comment in "frame.h", there is some fuzz here. Frameless +@@ -463,8 +530,8 @@ frame_find_by_id (struct frame_id id) + return NULL; + } + +-CORE_ADDR +-frame_pc_unwind (struct frame_info *this_frame) ++static CORE_ADDR ++frame_unwind_pc (struct frame_info *this_frame) + { + if (!this_frame->prev_pc.p) + { +@@ -503,6 +570,12 @@ frame_pc_unwind (struct frame_info *this + } + + CORE_ADDR ++frame_pc_unwind (struct frame_info *this_frame) ++{ ++ return frame_unwind_pc (skip_inlined_frames (this_frame)); ++} ++ ++CORE_ADDR + get_frame_func (struct frame_info *this_frame) + { + struct frame_info *next_frame = this_frame->next; +@@ -1226,7 +1299,6 @@ frame_register_unwind_location (struct f + static struct frame_info * + get_prev_frame_1 (struct frame_info *this_frame) + { +- struct frame_info *prev_frame; + struct frame_id this_id; + struct gdbarch *gdbarch; + +@@ -1266,6 +1338,14 @@ get_prev_frame_1 (struct frame_info *thi + this_frame->prev_p = 1; + this_frame->stop_reason = UNWIND_NO_REASON; + ++ /* If we are unwinding from an inline frame, all of the below tests ++ were already performed when we unwound from the next non-inline ++ frame. We must skip them, since we can not get THIS_FRAME's ID ++ until we have unwound all the way down to the previous non-inline ++ frame. */ ++ if (get_frame_type (this_frame) == INLINE_FRAME) ++ return get_prev_frame_raw (this_frame); ++ + /* Check that this frame's ID was valid. If it wasn't, don't try to + unwind to the prev frame. Be careful to not apply this test to + the sentinel frame. */ +@@ -1333,7 +1413,8 @@ get_prev_frame_1 (struct frame_info *thi + if (this_frame->level > 0 + && gdbarch_pc_regnum (gdbarch) >= 0 + && get_frame_type (this_frame) == NORMAL_FRAME +- && get_frame_type (this_frame->next) == NORMAL_FRAME) ++ && (get_frame_type (this_frame->next) == NORMAL_FRAME ++ || get_frame_type (this_frame->next) == INLINE_FRAME)) + { + int optimized, realnum, nrealnum; + enum lval_type lval, nlval; +@@ -1362,6 +1443,17 @@ get_prev_frame_1 (struct frame_info *thi + } + } + ++ return get_prev_frame_raw (this_frame); ++} ++ ++/* Construct a new "struct frame_info" and link it previous to ++ this_frame. */ ++ ++static struct frame_info * ++get_prev_frame_raw (struct frame_info *this_frame) ++{ ++ struct frame_info *prev_frame; ++ + /* Allocate the new frame but do not wire it in to the frame chain. + Some (bad) code in INIT_FRAME_EXTRA_INFO tries to look along + frame->next to pull some fancy tricks (of course such code is, by +@@ -1484,7 +1576,7 @@ get_prev_frame (struct frame_info *this_ + the main function when we created the dummy frame, the dummy frame will + point inside the main function. */ + if (this_frame->level >= 0 +- && get_frame_type (this_frame) != DUMMY_FRAME ++ && get_frame_type (this_frame) == NORMAL_FRAME + && !backtrace_past_main + && inside_main_func (this_frame)) + /* Don't unwind past main(). Note, this is done _before_ the +@@ -1529,8 +1621,9 @@ get_prev_frame (struct frame_info *this_ + from main returns directly to the caller of main. Since we don't + stop at main, we should at least stop at the entry point of the + application. */ +- if (!backtrace_past_entry +- && get_frame_type (this_frame) != DUMMY_FRAME && this_frame->level >= 0 ++ if (this_frame->level >= 0 ++ && get_frame_type (this_frame) == NORMAL_FRAME ++ && !backtrace_past_entry + && inside_entry_func (this_frame)) + { + frame_debug_got_null_frame (this_frame, "inside entry func"); +@@ -1541,7 +1634,8 @@ get_prev_frame (struct frame_info *this_ + like a SIGSEGV or a dummy frame, and hence that NORMAL frames + will never unwind a zero PC. */ + if (this_frame->level > 0 +- && get_frame_type (this_frame) == NORMAL_FRAME ++ && (get_frame_type (this_frame) == NORMAL_FRAME ++ || get_frame_type (this_frame) == INLINE_FRAME) + && get_frame_type (get_next_frame (this_frame)) == NORMAL_FRAME + && get_frame_pc (this_frame) == 0) + { +@@ -1566,7 +1660,7 @@ CORE_ADDR + get_frame_pc (struct frame_info *frame) + { + gdb_assert (frame->next != NULL); +- return frame_pc_unwind (frame->next); ++ return frame_unwind_pc (frame->next); + } + + /* Return an address that falls within THIS_FRAME's code block. */ +@@ -1611,17 +1705,58 @@ get_frame_address_in_block (struct frame + We check the type of NEXT_FRAME first, since it is already + known; frame type is determined by the unwinder, and since + we have THIS_FRAME we've already selected an unwinder for +- NEXT_FRAME. */ ++ NEXT_FRAME. ++ ++ If the next frame is inlined, we need to keep going until we find ++ the real function - for instance, if a signal handler is invoked ++ while in an inlined function, then the code address of the ++ "calling" normal function should not be adjusted either. */ ++ ++ while (get_frame_type (next_frame) == INLINE_FRAME) ++ next_frame = next_frame->next; ++ + if (get_frame_type (next_frame) == NORMAL_FRAME +- && get_frame_type (this_frame) == NORMAL_FRAME) ++ && (get_frame_type (this_frame) == NORMAL_FRAME ++ || get_frame_type (this_frame) == INLINE_FRAME)) + return pc - 1; + + return pc; + } + +-static int +-pc_notcurrent (struct frame_info *frame) ++void ++find_frame_sal (struct frame_info *frame, struct symtab_and_line *sal) + { ++ struct frame_info *next_frame; ++ int notcurrent; ++ ++ /* If the next frame represents an inlined function call, this frame's ++ sal is the "call site" of that inlined function, which can not ++ be inferred from get_frame_pc. */ ++ next_frame = get_next_frame (frame); ++ if (frame_inlined_callees (frame) > 0) ++ { ++ struct symbol *sym; ++ ++ if (next_frame) ++ sym = get_frame_function (next_frame); ++ else ++ sym = inline_skipped_symbol (inferior_ptid); ++ ++ init_sal (sal); ++ if (SYMBOL_LINE (sym) != 0) ++ { ++ sal->symtab = SYMBOL_SYMTAB (sym); ++ sal->line = SYMBOL_LINE (sym); ++ } ++ else ++ /* If the symbol does not have a location, we don't know where ++ the call site is. Do not pretend to. This is jarring, but ++ we can't do much better. */ ++ sal->pc = get_frame_pc (frame); ++ ++ return; ++ } ++ + /* If FRAME is not the innermost frame, that normally means that + FRAME->pc points at the return instruction (which is *after* the + call instruction), and we want to get the line containing the +@@ -1631,15 +1766,8 @@ pc_notcurrent (struct frame_info *frame) + PC and such a PC indicates the current (rather than next) + instruction/line, consequently, for such cases, want to get the + line containing fi->pc. */ +- struct frame_info *next = get_next_frame (frame); +- int notcurrent = (next != NULL && get_frame_type (next) == NORMAL_FRAME); +- return notcurrent; +-} +- +-void +-find_frame_sal (struct frame_info *frame, struct symtab_and_line *sal) +-{ +- (*sal) = find_pc_line (get_frame_pc (frame), pc_notcurrent (frame)); ++ notcurrent = (get_frame_pc (frame) != get_frame_address_in_block (frame)); ++ (*sal) = find_pc_line (get_frame_pc (frame), notcurrent); + } + + /* Per "frame.h", return the ``address'' of the frame. Code should +Index: gdb-6.8.50.20090228/gdb/frame.h +=================================================================== +--- gdb-6.8.50.20090228.orig/gdb/frame.h 2009-02-05 18:28:20.000000000 +0100 ++++ gdb-6.8.50.20090228/gdb/frame.h 2009-03-02 01:04:45.000000000 +0100 +@@ -34,6 +34,9 @@ + frame_unwind_WHAT...(): Unwind THIS frame's WHAT from the NEXT + frame. + ++ get_stack_frame_WHAT...(): Get WHAT for THIS frame, but if THIS is ++ inlined, skip to the containing stack frame. ++ + put_frame_WHAT...(): Put a value into this frame (unsafe, need to + invalidate the frame / regcache afterwards) (better name more + strongly hinting at its unsafeness) +@@ -101,6 +104,10 @@ struct frame_id + Typically, it is set to the address of the entry point of the + frame's function (as returned by get_frame_func). + ++ For inlined functions (INLINE_DEPTH != 0), this is the address of ++ the first executed instruction in the block corresponding to the ++ inlined function. ++ + This field is valid only if code_addr_p is true. Otherwise, this + frame is considered to have a wildcard code address, i.e. one that + matches every address value in frame comparisons. */ +@@ -122,6 +129,10 @@ struct frame_id + unsigned int stack_addr_p : 1; + unsigned int code_addr_p : 1; + unsigned int special_addr_p : 1; ++ ++ /* The inline depth of this frame. A frame representing a "called" ++ inlined function will have this set to a nonzero value. */ ++ int inline_depth; + }; + + /* Methods for constructing and comparing Frame IDs. */ +@@ -157,6 +168,10 @@ extern struct frame_id frame_id_build_wi + non-zero .base). */ + extern int frame_id_p (struct frame_id l); + ++/* Returns non-zero when L is a valid frame representing an inlined ++ function. */ ++extern int frame_id_inlined_p (struct frame_id l); ++ + /* Returns non-zero when L and R identify the same frame, or, if + either L or R have a zero .func, then the same frame base. */ + extern int frame_id_eq (struct frame_id l, struct frame_id r); +@@ -177,6 +192,9 @@ enum frame_type + /* A fake frame, created by GDB when performing an inferior function + call. */ + DUMMY_FRAME, ++ /* A frame representing an inlined function, associated with an ++ upcoming (next, inner, younger) NORMAL_FRAME. */ ++ INLINE_FRAME, + /* In a signal handler, various OSs handle this in various ways. + The main thing is that the frame may be far from normal. */ + SIGTRAMP_FRAME, +@@ -345,6 +363,7 @@ extern CORE_ADDR get_frame_base (struct + + instead, since that avoids the bug. */ + extern struct frame_id get_frame_id (struct frame_info *fi); ++extern struct frame_id get_stack_frame_id (struct frame_info *fi); + extern struct frame_id frame_unwind_id (struct frame_info *next_frame); + + /* Assuming that a frame is `normal', return its base-address, or 0 if +Index: gdb-6.8.50.20090228/gdb/gdbthread.h +=================================================================== +--- gdb-6.8.50.20090228.orig/gdb/gdbthread.h 2009-03-02 01:01:15.000000000 +0100 ++++ gdb-6.8.50.20090228/gdb/gdbthread.h 2009-03-02 01:04:45.000000000 +0100 +@@ -83,6 +83,13 @@ struct thread_info + This is how we know when we step into a subroutine call, and how + to set the frame for the breakpoint used to step out. */ + struct frame_id step_frame_id; ++ ++ /* Similarly, the frame ID of the underlying stack frame (skipping any ++ inlined frames). */ ++ struct frame_id step_stack_frame_id; ++ ++ /* The source file and line at the beginning of the current step ++ operation. Only valid when step_frame_id is set. */ + int current_line; + struct symtab *current_symtab; + +Index: gdb-6.8.50.20090228/gdb/infcall.c +=================================================================== +--- gdb-6.8.50.20090228.orig/gdb/infcall.c 2009-03-02 01:01:15.000000000 +0100 ++++ gdb-6.8.50.20090228/gdb/infcall.c 2009-03-02 01:04:45.000000000 +0100 +@@ -898,15 +898,8 @@ The program being debugged exited while + + if (unwind_on_signal_p) + { +- /* The user wants the context restored. */ +- +- /* We must get back to the frame we were before the +- dummy call. */ +- dummy_frame_pop (dummy_id); +- +- /* We also need to restore inferior status to that before the +- dummy call. */ +- restore_inferior_status (inf_status); ++ /* The user wants the context restored. Calling error will ++ run inf_status_cleanup, which does all the work. */ + + /* FIXME: Insert a bunch of wrap_here; name can be very + long if it's a C++ name with arguments and stuff. */ +Index: gdb-6.8.50.20090228/gdb/infcmd.c +=================================================================== +--- gdb-6.8.50.20090228.orig/gdb/infcmd.c 2009-03-02 01:01:15.000000000 +0100 ++++ gdb-6.8.50.20090228/gdb/infcmd.c 2009-03-02 01:04:45.000000000 +0100 +@@ -52,6 +52,7 @@ + #include "cli/cli-decode.h" + #include "gdbthread.h" + #include "valprint.h" ++#include "inline-frame.h" + + /* Functions exported for general use, in inferior.h: */ + +@@ -744,6 +745,17 @@ Can't resume all threads and specify pro + continue_1 (all_threads); + } + ++/* Record the starting point of a "step" or "next" command. */ ++ ++static void ++set_step_frame (struct thread_info *tp) ++{ ++ struct symtab_and_line sal; ++ ++ find_frame_sal (get_current_frame (), &sal); ++ set_step_info (tp, get_current_frame (), sal); ++} ++ + /* Step until outside of current statement. */ + + static void +@@ -921,6 +933,20 @@ step_once (int skip_subroutines, int sin + THREAD is set. */ + struct thread_info *tp = inferior_thread (); + clear_proceed_status (); ++ set_step_frame (tp); ++ ++ /* Step at an inlined function behaves like "down". */ ++ if (!skip_subroutines && !single_inst ++ && inline_skipped_frames (inferior_ptid)) ++ { ++ step_into_inline_frame (inferior_ptid); ++ if (count > 1) ++ step_once (skip_subroutines, single_inst, count - 1, thread); ++ else ++ /* Pretend that we've stopped. */ ++ normal_stop (); ++ return; ++ } + + frame = get_current_frame (); + tp->step_frame_id = get_frame_id (frame); +@@ -1173,6 +1199,7 @@ until_next_command (int from_tty) + clear_proceed_status (); + + frame = get_current_frame (); ++ set_step_frame (tp); + + /* Step until either exited from this function or greater + than the current line (if in symbolic section) or pc (if +@@ -1200,7 +1227,6 @@ until_next_command (int from_tty) + } + + tp->step_over_calls = STEP_OVER_ALL; +- tp->step_frame_id = get_frame_id (frame); + + tp->step_multi = 0; /* Only one call to proceed */ + +@@ -1533,6 +1559,37 @@ finish_command (char *arg, int from_tty) + + clear_proceed_status (); + ++ /* Finishing from an inline frame is completely different. We don't ++ try to show the "return value" - no way to locate it. So we do ++ not need a completion. */ ++ if (get_frame_type (get_selected_frame (_("No selected frame."))) ++ == INLINE_FRAME) ++ { ++ struct thread_info *tp = inferior_thread (); ++ ++ /* Claim we are stepping in the calling frame. An empty step ++ range means that we will stop once we aren't in a function ++ called by that frame. We don't use the magic "1" value for ++ step_range_end, because then infrun will think this is nexti, ++ and not step over the rest of this inlined function call. */ ++ struct symtab_and_line empty_sal; ++ init_sal (&empty_sal); ++ set_step_info (tp, frame, empty_sal); ++ tp->step_range_start = tp->step_range_end = get_frame_pc (frame); ++ tp->step_over_calls = STEP_OVER_ALL; ++ ++ /* Print info on the selected frame, including level number but not ++ source. */ ++ if (from_tty) ++ { ++ printf_filtered (_("Run till exit from ")); ++ print_stack_frame (get_selected_frame (NULL), 1, LOCATION); ++ } ++ ++ proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 1); ++ return; ++ } ++ + /* Find the function we will return from. */ + + function = find_pc_function (get_frame_pc (get_selected_frame (NULL))); +Index: gdb-6.8.50.20090228/gdb/inferior.h +=================================================================== +--- gdb-6.8.50.20090228.orig/gdb/inferior.h 2009-03-02 01:01:15.000000000 +0100 ++++ gdb-6.8.50.20090228/gdb/inferior.h 2009-03-02 01:04:45.000000000 +0100 +@@ -259,6 +259,9 @@ extern void error_is_running (void); + /* Calls error_is_running if the current thread is running. */ + extern void ensure_not_running (void); + ++void set_step_info (struct thread_info *tp, struct frame_info *frame, ++ struct symtab_and_line sal); ++ + /* From infcmd.c */ + + extern void tty_command (char *, int); +Index: gdb-6.8.50.20090228/gdb/infrun.c +=================================================================== +--- gdb-6.8.50.20090228.orig/gdb/infrun.c 2009-03-02 01:04:32.000000000 +0100 ++++ gdb-6.8.50.20090228/gdb/infrun.c 2009-03-02 01:04:45.000000000 +0100 +@@ -48,6 +48,7 @@ + #include "gdb_assert.h" + #include "mi/mi-common.h" + #include "event-top.h" ++#include "inline-frame.h" + + /* Prototypes for local functions */ + +@@ -205,7 +206,7 @@ static unsigned char *signal_program; + + /* Value to pass to target_resume() to cause all threads to resume */ + +-#define RESUME_ALL (pid_to_ptid (-1)) ++#define RESUME_ALL minus_one_ptid + + /* Command list pointer for the "stop" placeholder. */ + +@@ -1151,6 +1152,8 @@ a command like `return' or `jump' to con + step = 0; + } + ++ clear_inline_frame_state (resume_ptid); ++ + if (debug_displaced + && use_displaced_stepping (gdbarch) + && tp->trap_expected) +@@ -1192,6 +1195,7 @@ clear_proceed_status_thread (struct thre + tp->step_range_start = 0; + tp->step_range_end = 0; + tp->step_frame_id = null_frame_id; ++ tp->step_stack_frame_id = null_frame_id; + tp->step_over_calls = STEP_OVER_UNDEBUGGABLE; + tp->stop_requested = 0; + +@@ -1536,6 +1540,9 @@ init_wait_for_inferior (void) + init_infwait_state (); + + displaced_step_clear (); ++ ++ /* Discard any skipped inlined frames. */ ++ clear_inline_frame_state (minus_one_ptid); + } + + +@@ -1591,7 +1598,7 @@ struct execution_control_state + int wait_some_more; + }; + +-void init_execution_control_state (struct execution_control_state *ecs); ++static void init_execution_control_state (struct execution_control_state *ecs); + + void handle_inferior_event (struct execution_control_state *ecs); + +@@ -1949,10 +1956,21 @@ fetch_inferior_event (void *client_data) + display_gdb_prompt (0); + } + ++/* Record the frame and location we're currently stepping through. */ ++void ++set_step_info (struct thread_info *tp, struct frame_info *frame, ++ struct symtab_and_line sal) ++{ ++ tp->step_frame_id = get_frame_id (frame); ++ tp->step_stack_frame_id = get_stack_frame_id (frame); ++ tp->current_symtab = sal.symtab; ++ tp->current_line = sal.line; ++} ++ + /* Prepare an execution control state for looping through a + wait_for_inferior-type loop. */ + +-void ++static void + init_execution_control_state (struct execution_control_state *ecs) + { + ecs->random_signal = 0; +@@ -1963,16 +1981,10 @@ init_execution_control_state (struct exe + void + init_thread_stepping_state (struct thread_info *tss) + { +- struct symtab_and_line sal; +- + tss->stepping_over_breakpoint = 0; + tss->step_after_step_resume_breakpoint = 0; + tss->stepping_through_solib_after_catch = 0; + tss->stepping_through_solib_catchpoints = NULL; +- +- sal = find_pc_line (tss->prev_pc, 0); +- tss->current_line = sal.line; +- tss->current_symtab = sal.symtab; + } + + /* Return the cached copy of the last pid/waitstatus returned by +@@ -2186,6 +2198,22 @@ deal_with_syscall_event (struct executio + } + } + ++static int ++stepped_in_from (struct frame_info *frame, struct frame_id step_frame_id) ++{ ++ for (frame = get_prev_frame (frame); ++ frame != NULL; ++ frame = get_prev_frame (frame)) ++ { ++ if (frame_id_eq (get_frame_id (frame), step_frame_id)) ++ return 1; ++ if (get_frame_type (frame) != INLINE_FRAME) ++ break; ++ } ++ ++ return 0; ++} ++ + /* Given an execution control state that has been freshly filled in + by an event from the inferior, figure out what it means and take + appropriate action. */ +@@ -2880,6 +2908,12 @@ targets should add new threads to the th + ecs->random_signal = 0; + stopped_by_random_signal = 0; + ++ /* Hide inlined functions starting here, unless we just performed stepi or ++ nexti. After stepi and nexti, always show the innermost frame (not any ++ inline function call sites). */ ++ if (ecs->event_thread->step_range_end != 1) ++ skip_inline_frames (ecs->ptid); ++ + if (ecs->event_thread->stop_signal == TARGET_SIGNAL_TRAP + && ecs->event_thread->trap_expected + && gdbarch_single_step_through_delay_p (current_gdbarch) +@@ -3112,8 +3146,8 @@ process_event_stop_test: + && ecs->event_thread->stop_signal != TARGET_SIGNAL_0 + && (ecs->event_thread->step_range_start <= stop_pc + && stop_pc < ecs->event_thread->step_range_end) +- && frame_id_eq (get_frame_id (get_current_frame ()), +- ecs->event_thread->step_frame_id) ++ && frame_id_eq (get_stack_frame_id (get_current_frame ()), ++ ecs->event_thread->step_stack_frame_id) + && ecs->event_thread->step_resume_breakpoint == NULL) + { + /* The inferior is about to take a signal that will take it +@@ -3499,10 +3533,10 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME ( + NOTE: frame_id_eq will never report two invalid frame IDs as + being equal, so to get into this block, both the current and + previous frame must have valid frame IDs. */ +- if (!frame_id_eq (get_frame_id (get_current_frame ()), +- ecs->event_thread->step_frame_id) ++ if (!frame_id_eq (get_stack_frame_id (get_current_frame ()), ++ ecs->event_thread->step_stack_frame_id) + && (frame_id_eq (frame_unwind_id (get_current_frame ()), +- ecs->event_thread->step_frame_id) ++ ecs->event_thread->step_stack_frame_id) + || execution_direction == EXEC_REVERSE)) + { + CORE_ADDR real_stop_pc; +@@ -3745,6 +3779,82 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME ( + return; + } + ++ /* Look for "calls" to inlined functions, part one. If the inline ++ frame machinery detected some skipped call sites, we have entered ++ a new inline function. */ ++ ++ if (frame_id_eq (get_frame_id (get_current_frame ()), ++ ecs->event_thread->step_frame_id) ++ && inline_skipped_frames (ecs->ptid)) ++ { ++ struct symtab_and_line call_sal; ++ ++ if (debug_infrun) ++ fprintf_unfiltered (gdb_stdlog, ++ "infrun: stepped into inlined function\n"); ++ ++ find_frame_sal (get_current_frame (), &call_sal); ++ ++ if (ecs->event_thread->step_over_calls != STEP_OVER_ALL) ++ { ++ /* For "step", we're going to stop. But if the call site ++ for this inlined function is on the same source line as ++ we were previously stepping, go down into the function ++ first. Otherwise stop at the call site. */ ++ ++ if (call_sal.line == ecs->event_thread->current_line ++ && call_sal.symtab == ecs->event_thread->current_symtab) ++ step_into_inline_frame (ecs->ptid); ++ ++ ecs->event_thread->stop_step = 1; ++ print_stop_reason (END_STEPPING_RANGE, 0); ++ stop_stepping (ecs); ++ return; ++ } ++ else ++ { ++ /* For "next", we should stop at the call site if it is on a ++ different source line. Otherwise continue through the ++ inlined function. */ ++ if (call_sal.line == ecs->event_thread->current_line ++ && call_sal.symtab == ecs->event_thread->current_symtab) ++ keep_going (ecs); ++ else ++ { ++ ecs->event_thread->stop_step = 1; ++ print_stop_reason (END_STEPPING_RANGE, 0); ++ stop_stepping (ecs); ++ } ++ return; ++ } ++ } ++ ++ /* Look for "calls" to inlined functions, part two. If we are still ++ in the same real function we were stepping through, but we have ++ to go further up to find the exact frame ID, we are stepping ++ through a more inlined call beyond its call site. */ ++ ++ if (get_frame_type (get_current_frame ()) == INLINE_FRAME ++ && !frame_id_eq (get_frame_id (get_current_frame ()), ++ ecs->event_thread->step_frame_id) ++ && stepped_in_from (get_current_frame (), ++ ecs->event_thread->step_frame_id)) ++ { ++ if (debug_infrun) ++ fprintf_unfiltered (gdb_stdlog, ++ "infrun: stepping through inlined function\n"); ++ ++ if (ecs->event_thread->step_over_calls == STEP_OVER_ALL) ++ keep_going (ecs); ++ else ++ { ++ ecs->event_thread->stop_step = 1; ++ print_stop_reason (END_STEPPING_RANGE, 0); ++ stop_stepping (ecs); ++ } ++ return; ++ } ++ + if ((stop_pc == stop_pc_sal.pc) + && (ecs->event_thread->current_line != stop_pc_sal.line + || ecs->event_thread->current_symtab != stop_pc_sal.symtab)) +@@ -3770,9 +3880,7 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME ( + + ecs->event_thread->step_range_start = stop_pc_sal.pc; + ecs->event_thread->step_range_end = stop_pc_sal.end; +- ecs->event_thread->step_frame_id = get_frame_id (get_current_frame ()); +- ecs->event_thread->current_line = stop_pc_sal.line; +- ecs->event_thread->current_symtab = stop_pc_sal.symtab; ++ set_step_info (ecs->event_thread, get_current_frame (), stop_pc_sal); + + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, "infrun: keep going\n"); +@@ -5024,6 +5132,7 @@ struct inferior_status + CORE_ADDR step_range_start; + CORE_ADDR step_range_end; + struct frame_id step_frame_id; ++ struct frame_id step_stack_frame_id; + enum step_over_calls_kind step_over_calls; + CORE_ADDR step_resume_break_address; + int stop_after_trap; +@@ -5053,6 +5162,7 @@ save_inferior_status (void) + inf_status->step_range_start = tp->step_range_start; + inf_status->step_range_end = tp->step_range_end; + inf_status->step_frame_id = tp->step_frame_id; ++ inf_status->step_stack_frame_id = tp->step_stack_frame_id; + inf_status->step_over_calls = tp->step_over_calls; + inf_status->stop_after_trap = stop_after_trap; + inf_status->stop_soon = inf->stop_soon; +@@ -5106,6 +5216,7 @@ restore_inferior_status (struct inferior + tp->step_range_start = inf_status->step_range_start; + tp->step_range_end = inf_status->step_range_end; + tp->step_frame_id = inf_status->step_frame_id; ++ tp->step_stack_frame_id = inf_status->step_stack_frame_id; + tp->step_over_calls = inf_status->step_over_calls; + stop_after_trap = inf_status->stop_after_trap; + inf->stop_soon = inf_status->stop_soon; +Index: gdb-6.8.50.20090228/gdb/inline-frame.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8.50.20090228/gdb/inline-frame.c 2009-03-02 01:04:45.000000000 +0100 +@@ -0,0 +1,382 @@ ++/* Inline frame unwinder for GDB. ++ ++ Copyright (C) 2008 Free Software Foundation, Inc. ++ ++ This file is part of GDB. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++#include "defs.h" ++#include "addrmap.h" ++#include "block.h" ++#include "frame-unwind.h" ++#include "inferior.h" ++#include "symtab.h" ++#include "vec.h" ++ ++#include "gdb_assert.h" ++ ++/* We need to save a few variables for every thread stopped at the ++ virtual call site of an inlined function. If there was always a ++ "struct thread_info", we could hang it off that; in the mean time, ++ keep our own list. */ ++struct inline_state ++{ ++ /* The thread this data relates to. It should be a currently ++ stopped thread; we assume thread IDs never change while the ++ thread is stopped. */ ++ ptid_t ptid; ++ ++ /* The number of inlined functions we are skipping. Each of these ++ functions can be stepped in to. */ ++ int skipped_frames; ++ ++ /* Only valid if SKIPPED_FRAMES is non-zero. This is the PC used ++ when calculating SKIPPED_FRAMES; used to check whether we have ++ moved to a new location by user request. If so, we invalidate ++ any skipped frames. */ ++ CORE_ADDR saved_pc; ++ ++ /* Only valid if SKIPPED_FRAMES is non-zero. This is the symbol ++ of the outermost skipped inline function. It's used to find the ++ call site of the current frame. */ ++ struct symbol *skipped_symbol; ++}; ++ ++typedef struct inline_state inline_state_s; ++DEF_VEC_O(inline_state_s); ++ ++static VEC(inline_state_s) *inline_states; ++ ++/* Locate saved inlined frame state for PTID, if it exists. */ ++ ++static struct inline_state * ++find_inline_frame_state (ptid_t ptid) ++{ ++ struct inline_state *state; ++ int ix; ++ ++ for (ix = 0; VEC_iterate (inline_state_s, inline_states, ix, state); ix++) ++ { ++ if (ptid_equal (state->ptid, ptid)) ++ return state; ++ } ++ ++ return NULL; ++} ++ ++/* Allocate saved inlined frame state for PTID. */ ++ ++static struct inline_state * ++allocate_inline_frame_state (ptid_t ptid) ++{ ++ struct inline_state *state; ++ ++ state = VEC_safe_push (inline_state_s, inline_states, NULL); ++ memset (state, 0, sizeof (*state)); ++ state->ptid = ptid; ++ ++ return state; ++} ++ ++/* Forget about any hidden inlined functions in PTID, which is new or ++ about to be resumed. If PTID is minus_one_ptid, forget about all ++ hidden inlined functions. */ ++ ++void ++clear_inline_frame_state (ptid_t ptid) ++{ ++ struct inline_state *state; ++ int ix; ++ ++ if (ptid_equal (ptid, minus_one_ptid)) ++ { ++ VEC_free (inline_state_s, inline_states); ++ return; ++ } ++ ++ for (ix = 0; VEC_iterate (inline_state_s, inline_states, ix, state); ix++) ++ if (ptid_equal (state->ptid, ptid)) ++ { ++ VEC_unordered_remove (inline_state_s, inline_states, ix); ++ return; ++ } ++} ++ ++static void ++inline_frame_this_id (struct frame_info *this_frame, ++ void **this_cache, ++ struct frame_id *this_id) ++{ ++ struct symbol *func; ++ ++ /* In order to have a stable frame ID for a given inline function, ++ we must get the stack / special addresses from the underlying ++ real frame's this_id method. So we must call get_prev_frame. ++ Because we are inlined into some function, there must be previous ++ frames, so this is safe - as long as we're careful not to ++ create any cycles. */ ++ *this_id = get_frame_id (get_prev_frame (this_frame)); ++ ++ /* We need a valid frame ID, so we need to be based on a valid ++ frame. FSF submission NOTE: this would be a good assertion to ++ apply to all frames, all the time. That would fix the ambiguity ++ of null_frame_id (between "no/any frame" and "the outermost ++ frame"). This will take work. */ ++ gdb_assert (frame_id_p (*this_id)); ++ ++ /* Future work NOTE: Alexandre Oliva applied a patch to GCC 4.3 ++ which generates DW_AT_entry_pc for inlined functions when ++ possible. If this attribute is available, we should use it ++ in the frame ID (and eventually, to set breakpoints). */ ++ func = get_frame_function (this_frame); ++ gdb_assert (func != NULL); ++ (*this_id).code_addr = BLOCK_START (SYMBOL_BLOCK_VALUE (func)); ++ (*this_id).inline_depth++; ++} ++ ++static struct value * ++inline_frame_prev_register (struct frame_info *this_frame, void **this_cache, ++ int regnum) ++{ ++ /* Use get_frame_register_value instead of ++ frame_unwind_got_register, to avoid requiring this frame's ID. ++ This frame's ID depends on the previous frame's ID (unusual), and ++ the previous frame's ID depends on this frame's unwound ++ registers. If unwinding registers from this frame called ++ get_frame_id, there would be a loop. ++ ++ Do not copy this code into any other unwinder! Inlined functions ++ are special; other unwinders must not have a dependency on the ++ previous frame's ID, and therefore can and should use ++ frame_unwind_got_register instead. */ ++ return get_frame_register_value (this_frame, regnum); ++} ++ ++/* Check whether we are at an inlining site that does not already ++ have an associated frame. */ ++ ++static int ++inline_frame_sniffer (const struct frame_unwind *self, ++ struct frame_info *this_frame, ++ void **this_cache) ++{ ++ CORE_ADDR this_pc; ++ struct block *frame_block, *cur_block; ++ int depth; ++ struct frame_info *next_frame; ++ struct inline_state *state = find_inline_frame_state (inferior_ptid); ++ ++ this_pc = get_frame_address_in_block (this_frame); ++ frame_block = block_for_pc (this_pc); ++ if (frame_block == NULL) ++ return 0; ++ ++ /* Calculate DEPTH, the number of inlined functions at this ++ location. */ ++ depth = 0; ++ cur_block = frame_block; ++ while (BLOCK_SUPERBLOCK (cur_block)) ++ { ++ if (block_inlined_p (cur_block)) ++ depth++; ++ ++ cur_block = BLOCK_SUPERBLOCK (cur_block); ++ } ++ ++ /* Check how many inlined functions already have frames. */ ++ for (next_frame = get_next_frame (this_frame); ++ next_frame && get_frame_type (next_frame) == INLINE_FRAME; ++ next_frame = get_next_frame (next_frame)) ++ { ++ gdb_assert (depth > 0); ++ depth--; ++ } ++ ++ /* If this is the topmost frame, or all frames above us are inlined, ++ then check whether we were requested to skip some frames (so they ++ can be stepped into later). */ ++ if (state != NULL && state->skipped_frames > 0 && next_frame == NULL) ++ { ++ if (this_pc != state->saved_pc) ++ state->skipped_frames = 0; ++ else ++ { ++ gdb_assert (depth >= state->skipped_frames); ++ depth -= state->skipped_frames; ++ } ++ } ++ ++ /* If all the inlined functions here already have frames, then pass ++ to the normal unwinder for this PC. */ ++ if (depth == 0) ++ return 0; ++ ++ /* If the next frame is an inlined function, but not the outermost, then ++ we are the next outer. If it is not an inlined function, then we ++ are the innermost inlined function of a different real frame. */ ++ return 1; ++} ++ ++const struct frame_unwind inline_frame_unwinder = { ++ INLINE_FRAME, ++ inline_frame_this_id, ++ inline_frame_prev_register, ++ NULL, ++ inline_frame_sniffer ++}; ++ ++const struct frame_unwind *const inline_frame_unwind = &inline_frame_unwinder; ++ ++/* Return non-zero if BLOCK, an inlined function block containing PC, ++ has a group of contiguous instructions starting at PC (but not ++ before it). */ ++ ++static int ++block_starting_point_at (CORE_ADDR pc, struct block *block) ++{ ++ struct blockvector *bv; ++ struct block *new_block; ++ ++ bv = blockvector_for_pc (pc, NULL); ++ if (BLOCKVECTOR_MAP (bv) == NULL) ++ return 0; ++ ++ new_block = addrmap_find (BLOCKVECTOR_MAP (bv), pc - 1); ++ if (new_block == NULL) ++ return 1; ++ ++ if (new_block == block || contained_in (new_block, block)) ++ return 0; ++ ++ /* The immediately preceeding address belongs to a different block, ++ which is not a child of this one. Treat this as an entrance into ++ BLOCK. */ ++ return 1; ++} ++ ++/* Skip all inlined functions whose call sites are at the current PC. ++ Frames for the hidden functions will not appear in the backtrace until the ++ user steps into them. */ ++ ++void ++skip_inline_frames (ptid_t ptid) ++{ ++ CORE_ADDR this_pc; ++ struct block *frame_block, *cur_block; ++ struct symbol *last_sym = NULL; ++ int skip_count = 0; ++ struct inline_state *state; ++ ++ /* This function is called right after reinitializing the frame ++ cache. We try not to do more unwinding than absolutely ++ necessary, for performance. */ ++ this_pc = get_frame_pc (get_current_frame ()); ++ frame_block = block_for_pc (this_pc); ++ ++ if (frame_block != NULL) ++ { ++ cur_block = frame_block; ++ while (BLOCK_SUPERBLOCK (cur_block)) ++ { ++ if (block_inlined_p (cur_block)) ++ { ++ /* See comments in inline_frame_this_id about this use ++ of BLOCK_START. */ ++ if (BLOCK_START (cur_block) == this_pc ++ || block_starting_point_at (this_pc, cur_block)) ++ { ++ skip_count++; ++ last_sym = BLOCK_FUNCTION (cur_block); ++ } ++ else ++ break; ++ } ++ cur_block = BLOCK_SUPERBLOCK (cur_block); ++ } ++ } ++ ++ gdb_assert (find_inline_frame_state (ptid) == NULL); ++ state = allocate_inline_frame_state (ptid); ++ state->skipped_frames = skip_count; ++ state->saved_pc = this_pc; ++ state->skipped_symbol = last_sym; ++ ++ if (skip_count != 0) ++ reinit_frame_cache (); ++} ++ ++/* Step into an inlined function by unhiding it. */ ++ ++void ++step_into_inline_frame (ptid_t ptid) ++{ ++ struct inline_state *state = find_inline_frame_state (ptid); ++ ++ gdb_assert (state != NULL && state->skipped_frames > 0); ++ state->skipped_frames--; ++ reinit_frame_cache (); ++} ++ ++/* Return the number of hidden functions inlined into the current ++ frame. */ ++ ++int ++inline_skipped_frames (ptid_t ptid) ++{ ++ struct inline_state *state = find_inline_frame_state (ptid); ++ ++ if (state == NULL) ++ return 0; ++ else ++ return state->skipped_frames; ++} ++ ++/* If one or more inlined functions are hidden, return the symbol for ++ the function inlined into the current frame. */ ++ ++struct symbol * ++inline_skipped_symbol (ptid_t ptid) ++{ ++ struct inline_state *state = find_inline_frame_state (ptid); ++ ++ gdb_assert (state != NULL); ++ return state->skipped_symbol; ++} ++ ++/* Return the number of functions inlined into THIS_FRAME. Some of ++ the callees may not have associated frames (see ++ skip_inline_frames). */ ++ ++int ++frame_inlined_callees (struct frame_info *this_frame) ++{ ++ struct frame_info *next_frame; ++ int inline_count = 0; ++ ++ /* First count how many inlined functions at this PC have frames ++ above FRAME (are inlined into FRAME). */ ++ for (next_frame = get_next_frame (this_frame); ++ next_frame && get_frame_type (next_frame) == INLINE_FRAME; ++ next_frame = get_next_frame (next_frame)) ++ inline_count++; ++ ++ /* Simulate some most-inner inlined frames which were suppressed, so ++ they can be stepped into later. If we are unwinding already ++ outer frames from some non-inlined frame this does not apply. */ ++ if (next_frame == NULL) ++ inline_count += inline_skipped_frames (inferior_ptid); ++ ++ return inline_count; ++} +Index: gdb-6.8.50.20090228/gdb/inline-frame.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8.50.20090228/gdb/inline-frame.h 2009-03-02 01:04:45.000000000 +0100 +@@ -0,0 +1,62 @@ ++/* Definitions for inline frame support. ++ ++ Copyright (C) 2008 Free Software Foundation, Inc. ++ ++ This file is part of GDB. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++#if !defined (INLINE_FRAME_H) ++#define INLINE_FRAME_H 1 ++ ++struct frame_info; ++struct frame_unwind; ++ ++/* The inline frame unwinder. */ ++ ++extern const struct frame_unwind *const inline_frame_unwind; ++ ++/* Skip all inlined functions whose call sites are at the current PC. ++ Frames for the hidden functions will not appear in the backtrace until the ++ user steps into them. */ ++ ++void skip_inline_frames (ptid_t ptid); ++ ++/* Forget about any hidden inlined functions in PTID, which is new or ++ about to be resumed. If PTID is minus_one_ptid, forget about all ++ hidden inlined functions. */ ++ ++void clear_inline_frame_state (ptid_t ptid); ++ ++/* Step into an inlined function by unhiding it. */ ++ ++void step_into_inline_frame (ptid_t ptid); ++ ++/* Return the number of hidden functions inlined into the current ++ frame. */ ++ ++int inline_skipped_frames (ptid_t ptid); ++ ++/* If one or more inlined functions are hidden, return the symbol for ++ the function inlined into the current frame. */ ++ ++struct symbol *inline_skipped_symbol (ptid_t ptid); ++ ++/* Return the number of functions inlined into THIS_FRAME. Some of ++ the callees may not have associated frames (see ++ skip_inline_frames). */ ++ ++int frame_inlined_callees (struct frame_info *this_frame); ++ ++#endif /* !defined (INLINE_FRAME_H) */ +Index: gdb-6.8.50.20090228/gdb/minsyms.c +=================================================================== +--- gdb-6.8.50.20090228.orig/gdb/minsyms.c 2009-03-02 01:04:32.000000000 +0100 ++++ gdb-6.8.50.20090228/gdb/minsyms.c 2009-03-02 01:04:45.000000000 +0100 +@@ -795,7 +795,7 @@ prim_record_minimal_symbol_and_info (con + + if (msym_bunch_index == BUNCH_SIZE) + { +- new = (struct msym_bunch *) xmalloc (sizeof (struct msym_bunch)); ++ new = XCALLOC (1, struct msym_bunch); + msym_bunch_index = 0; + new->next = msym_bunch; + msym_bunch = new; +Index: gdb-6.8.50.20090228/gdb/s390-tdep.c +=================================================================== +--- gdb-6.8.50.20090228.orig/gdb/s390-tdep.c 2009-02-22 02:02:19.000000000 +0100 ++++ gdb-6.8.50.20090228/gdb/s390-tdep.c 2009-03-02 01:04:45.000000000 +0100 +@@ -1182,6 +1182,7 @@ s390_prologue_frame_unwind_cache (struct + CORE_ADDR prev_sp; + int frame_pointer; + int size; ++ struct frame_info *next_frame; + + /* Try to find the function start address. If we can't find it, we don't + bother searching for it -- with modern compilers this would be mostly +@@ -1215,7 +1216,10 @@ s390_prologue_frame_unwind_cache (struct + /* FIXME: cagney/2004-05-01: This sanity check shouldn't be + needed, instead the code should simpliy rely on its + analysis. */ +- if (get_next_frame (this_frame) ++ next_frame = get_next_frame (this_frame); ++ while (next_frame && get_frame_type (next_frame) == INLINE_FRAME) ++ next_frame = get_next_frame (next_frame); ++ if (next_frame + && get_frame_type (get_next_frame (this_frame)) == NORMAL_FRAME) + return 0; + +@@ -1261,8 +1265,11 @@ s390_prologue_frame_unwind_cache (struct + This can only happen in an innermost frame. */ + /* FIXME: cagney/2004-05-01: This sanity check shouldn't be needed, + instead the code should simpliy rely on its analysis. */ ++ next_frame = get_next_frame (this_frame); ++ while (next_frame && get_frame_type (next_frame) == INLINE_FRAME) ++ next_frame = get_next_frame (next_frame); + if (size > 0 +- && (!get_next_frame (this_frame) ++ && (next_frame == NULL + || get_frame_type (get_next_frame (this_frame)) != NORMAL_FRAME)) + { + /* See the comment in s390_in_function_epilogue_p on why this is +Index: gdb-6.8.50.20090228/gdb/stack.c +=================================================================== +--- gdb-6.8.50.20090228.orig/gdb/stack.c 2009-03-02 01:01:15.000000000 +0100 ++++ gdb-6.8.50.20090228/gdb/stack.c 2009-03-02 01:04:45.000000000 +0100 +@@ -45,6 +45,7 @@ + #include "valprint.h" + #include "gdbthread.h" + #include "cp-support.h" ++#include "inline-frame.h" + + #include "gdb_assert.h" + #include +@@ -98,6 +99,30 @@ print_stack_frame_stub (void *args) + return 0; + } + ++/* Return 1 if we should display the address in addition to the location, ++ because we are in the middle of a statement. */ ++ ++static int ++frame_show_address (struct frame_info *frame, ++ struct symtab_and_line sal) ++{ ++ /* If there is a line number, but no PC, then there is no location ++ information associated with this sal. The only way that should ++ happen is for the call sites of inlined functions (SAL comes from ++ find_frame_sal). Otherwise, we would have some PC range if the ++ SAL came from a line table. */ ++ if (sal.line != 0 && sal.pc == 0 && sal.end == 0) ++ { ++ if (get_next_frame (frame) == NULL) ++ gdb_assert (inline_skipped_frames (inferior_ptid) > 0); ++ else ++ gdb_assert (get_frame_type (get_next_frame (frame)) == INLINE_FRAME); ++ return 0; ++ } ++ ++ return get_frame_pc (frame) != sal.pc; ++} ++ + /* Show or print a stack frame FRAME briefly. The output is format + according to PRINT_LEVEL and PRINT_WHAT printing the frame's + relative level, function name, argument list, and file name and +@@ -538,7 +563,7 @@ print_frame_info (struct frame_info *fra + { + int done = 0; + int mid_statement = ((print_what == SRC_LINE) +- && (get_frame_pc (frame) != sal.pc)); ++ && frame_show_address (frame, sal)); + + if (annotation_level) + done = identify_source_line (sal.symtab, sal.line, mid_statement, +@@ -591,7 +616,7 @@ find_frame_funname (struct frame_info *f + *funname = NULL; + *funlang = language_unknown; + +- func = find_pc_function (get_frame_address_in_block (frame)); ++ func = get_frame_function (frame); + if (func) + { + /* In certain pathological cases, the symtabs give the wrong +@@ -612,8 +637,13 @@ find_frame_funname (struct frame_info *f + changed (and we'll create a find_pc_minimal_function or some + such). */ + +- struct minimal_symbol *msymbol = +- lookup_minimal_symbol_by_pc (get_frame_address_in_block (frame)); ++ struct minimal_symbol *msymbol = NULL; ++ ++ /* Don't attempt to do this for inlined functions, which do not ++ have a corresponding minimal symbol. */ ++ if (!block_inlined_p (SYMBOL_BLOCK_VALUE (func))) ++ msymbol ++ = lookup_minimal_symbol_by_pc (get_frame_address_in_block (frame)); + + if (msymbol != NULL + && (SYMBOL_VALUE_ADDRESS (msymbol) +@@ -687,7 +717,7 @@ print_frame (struct frame_info *frame, i + } + get_user_print_options (&opts); + if (opts.addressprint) +- if (get_frame_pc (frame) != sal.pc || !sal.symtab ++ if (frame_show_address (frame, sal) || !sal.symtab + || print_what == LOC_AND_ADDRESS) + { + annotate_frame_address (); +@@ -867,8 +897,16 @@ parse_frame_specification_1 (const char + { + if (frame_id_eq (id, get_frame_id (fid))) + { +- while (frame_id_eq (id, frame_unwind_id (fid))) +- fid = get_prev_frame (fid); ++ struct frame_info *prev_frame; ++ ++ while (1) ++ { ++ prev_frame = get_prev_frame (fid); ++ if (!prev_frame ++ || !frame_id_eq (id, get_frame_id (prev_frame))) ++ break; ++ fid = prev_frame; ++ } + return fid; + } + } +@@ -1002,8 +1040,10 @@ frame_info (char *addr_exp, int from_tty + printf_filtered (_(" Outermost frame: %s\n"), + frame_stop_reason_string (reason)); + } +- +- if (calling_frame_info) ++ else if (get_frame_type (fi) == INLINE_FRAME) ++ printf_filtered (" inlined into frame %d", ++ frame_relative_level (get_prev_frame (fi))); ++ else + { + printf_filtered (" called by frame at "); + fputs_filtered (paddress (get_frame_base (calling_frame_info)), +@@ -1465,7 +1505,9 @@ print_frame_local_vars (struct frame_inf + if (print_block_frame_locals (block, frame, num_tabs, stream)) + values_printed = 1; + /* After handling the function's top-level block, stop. Don't +- continue to its superblock, the block of per-file symbols. */ ++ continue to its superblock, the block of per-file symbols. ++ Also do not continue to the containing function of an inlined ++ function. */ + if (BLOCK_FUNCTION (block)) + break; + block = BLOCK_SUPERBLOCK (block); +@@ -1536,7 +1578,9 @@ print_frame_label_vars (struct frame_inf + return; + + /* After handling the function's top-level block, stop. Don't +- continue to its superblock, the block of per-file symbols. */ ++ continue to its superblock, the block of per-file symbols. ++ Also do not continue to the containing function of an inlined ++ function. */ + if (BLOCK_FUNCTION (block)) + break; + block = BLOCK_SUPERBLOCK (block); +@@ -1874,6 +1918,9 @@ return_command (char *retval_exp, int fr + thisframe = get_selected_frame ("No selected frame."); + thisfun = get_frame_function (thisframe); + ++ if (get_frame_type (get_current_frame ()) == INLINE_FRAME) ++ error (_("Can not force return from an inlined function.")); ++ + /* Compute the return value. If the computation triggers an error, + let it bail. If the return type can't be handled, set + RETURN_VALUE to NULL, and QUERY_PREFIX to an informational +Index: gdb-6.8.50.20090228/gdb/symtab.c +=================================================================== +--- gdb-6.8.50.20090228.orig/gdb/symtab.c 2009-03-02 01:04:32.000000000 +0100 ++++ gdb-6.8.50.20090228/gdb/symtab.c 2009-03-02 01:06:36.000000000 +0100 +@@ -1414,11 +1414,14 @@ lookup_symbol_aux_local (const char *nam + sym = lookup_symbol_aux_block (name, linkage_name, block, domain); + if (sym != NULL) + return sym; ++ ++ if (BLOCK_FUNCTION (block) != NULL && block_inlined_p (block)) ++ break; + + block = BLOCK_SUPERBLOCK (block); + } + +- /* We've reached the global block without finding a result. */ ++ /* We've reached the edge of the function without finding a result. */ + + return NULL; + } +@@ -2675,6 +2678,7 @@ find_function_start_sal (struct symbol * + + CORE_ADDR pc; + struct symtab_and_line sal; ++ struct block *b, *function_block; + + pc = BLOCK_START (block); + fixup_symbol_section (sym, objfile); +@@ -2713,6 +2717,25 @@ find_function_start_sal (struct symbol * + + sal.pc = pc; + ++ /* Check if we are now inside an inlined function. If we can, ++ use the call site of the function instead. */ ++ b = block_for_pc_sect (sal.pc, SYMBOL_OBJ_SECTION (sym)); ++ function_block = NULL; ++ while (b != NULL) ++ { ++ if (BLOCK_FUNCTION (b) != NULL && block_inlined_p (b)) ++ function_block = b; ++ else if (BLOCK_FUNCTION (b) != NULL) ++ break; ++ b = BLOCK_SUPERBLOCK (b); ++ } ++ if (function_block != NULL ++ && SYMBOL_LINE (BLOCK_FUNCTION (function_block)) != 0) ++ { ++ sal.line = SYMBOL_LINE (BLOCK_FUNCTION (function_block)); ++ sal.symtab = SYMBOL_SYMTAB (BLOCK_FUNCTION (function_block)); ++ } ++ + return sal; + } + +@@ -3735,6 +3758,24 @@ add_macro_name (const char *name, const + datum->text, datum->word); + } + ++static void ++completion_list_add_fields (struct symbol *sym, char *sym_text, ++ int sym_text_len, char *text, char *word) ++{ ++ if (SYMBOL_CLASS (sym) == LOC_TYPEDEF) ++ { ++ struct type *t = SYMBOL_TYPE (sym); ++ enum type_code c = TYPE_CODE (t); ++ int j; ++ ++ if (c == TYPE_CODE_UNION || c == TYPE_CODE_STRUCT) ++ for (j = TYPE_N_BASECLASSES (t); j < TYPE_NFIELDS (t); j++) ++ if (TYPE_FIELD_NAME (t, j)) ++ completion_list_add_name (TYPE_FIELD_NAME (t, j), ++ sym_text, sym_text_len, text, word); ++ } ++} ++ + char ** + default_make_symbol_completion_list (char *text, char *word) + { +@@ -3747,9 +3788,9 @@ default_make_symbol_completion_list (cha + struct partial_symtab *ps; + struct minimal_symbol *msymbol; + struct objfile *objfile; +- struct block *b, *surrounding_static_block = 0; ++ struct block *b; ++ const struct block *surrounding_static_block, *surrounding_global_block; + struct dict_iterator iter; +- int j; + struct partial_symbol **psym; + /* The symbol we are completing on. Points in same buffer as text. */ + char *sym_text; +@@ -3859,41 +3900,43 @@ default_make_symbol_completion_list (cha + } + + /* Search upwards from currently selected frame (so that we can +- complete on local vars. */ ++ complete on local vars). Also catch fields of types defined in ++ this places which match our text string. Only complete on types ++ visible from current context. */ ++ ++ b = get_selected_block (0); ++ surrounding_static_block = block_static_block (b); ++ surrounding_global_block = block_global_block (b); ++ if (surrounding_static_block != NULL) ++ while (b != surrounding_static_block) ++ { ++ QUIT; + +- for (b = get_selected_block (0); b != NULL; b = BLOCK_SUPERBLOCK (b)) +- { +- if (!BLOCK_SUPERBLOCK (b)) +- { +- surrounding_static_block = b; /* For elmin of dups */ +- } ++ ALL_BLOCK_SYMBOLS (b, iter, sym) ++ { ++ COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, ++ word); ++ completion_list_add_fields (sym, sym_text, sym_text_len, text, ++ word); ++ } + +- /* Also catch fields of types defined in this places which match our +- text string. Only complete on types visible from current context. */ ++ /* Stop when we encounter an enclosing function. Do not stop for ++ non-inlined functions - the locals of the enclosing function ++ are in scope for a nested function. */ ++ if (BLOCK_FUNCTION (b) != NULL && block_inlined_p (b)) ++ break; ++ b = BLOCK_SUPERBLOCK (b); ++ } + +- ALL_BLOCK_SYMBOLS (b, iter, sym) +- { +- QUIT; +- COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word); +- if (SYMBOL_CLASS (sym) == LOC_TYPEDEF) +- { +- struct type *t = SYMBOL_TYPE (sym); +- enum type_code c = TYPE_CODE (t); ++ /* Add fields from the file's types; symbols will be added below. */ + +- if (c == TYPE_CODE_UNION || c == TYPE_CODE_STRUCT) +- { +- for (j = TYPE_N_BASECLASSES (t); j < TYPE_NFIELDS (t); j++) +- { +- if (TYPE_FIELD_NAME (t, j)) +- { +- completion_list_add_name (TYPE_FIELD_NAME (t, j), +- sym_text, sym_text_len, text, word); +- } +- } +- } +- } +- } +- } ++ if (surrounding_static_block != NULL) ++ ALL_BLOCK_SYMBOLS (surrounding_static_block, iter, sym) ++ completion_list_add_fields (sym, sym_text, sym_text_len, text, word); ++ ++ if (surrounding_global_block != NULL) ++ ALL_BLOCK_SYMBOLS (surrounding_global_block, iter, sym) ++ completion_list_add_fields (sym, sym_text, sym_text_len, text, word); + + /* Go through the symtabs and check the externs and statics for + symbols which match. */ +@@ -3912,9 +3955,6 @@ default_make_symbol_completion_list (cha + { + QUIT; + b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK); +- /* Don't do this block twice. */ +- if (b == surrounding_static_block) +- continue; + ALL_BLOCK_SYMBOLS (b, iter, sym) + { + COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word); +@@ -4381,6 +4421,25 @@ skip_prologue_using_sal (CORE_ADDR func_ + line mark the prologue -> body transition. */ + if (sal.line >= prologue_sal.line) + break; ++ ++ /* The line number is smaller. Check that it's from the ++ same function, not something inlined. If it's inlined, ++ then there is no point comparing the line numbers. */ ++ bl = block_for_pc (prologue_sal.end); ++ while (bl) ++ { ++ if (block_inlined_p (bl)) ++ break; ++ if (BLOCK_FUNCTION (bl)) ++ { ++ bl = NULL; ++ break; ++ } ++ bl = BLOCK_SUPERBLOCK (bl); ++ } ++ if (bl != NULL) ++ break; ++ + /* The case in which compiler's optimizer/scheduler has + moved instructions into the prologue. We look ahead in + the function looking for address ranges whose +Index: gdb-6.8.50.20090228/gdb/symtab.h +=================================================================== +--- gdb-6.8.50.20090228.orig/gdb/symtab.h 2009-03-02 01:01:15.000000000 +0100 ++++ gdb-6.8.50.20090228/gdb/symtab.h 2009-03-02 01:04:45.000000000 +0100 +@@ -556,9 +556,18 @@ struct symbol + + unsigned is_argument : 1; + +- /* Line number of definition. FIXME: Should we really make the assumption +- that nobody will try to debug files longer than 64K lines? What about +- machine generated programs? */ ++ /* Whether this is an inlined function (class LOC_BLOCK only). */ ++ unsigned is_inlined : 1; ++ ++ /* Line number of this symbol's definition, except for inlined ++ functions. For an inlined function (class LOC_BLOCK and ++ SYMBOL_INLINED set) this is the line number of the function's call ++ site. Inlined function symbols are not definitions, and they are ++ never found by symbol table lookup. ++ ++ FIXME: Should we really make the assumption that nobody will try ++ to debug files longer than 64K lines? What about machine ++ generated programs? */ + + unsigned short line; + +@@ -589,6 +598,7 @@ struct symbol + #define SYMBOL_DOMAIN(symbol) (symbol)->domain + #define SYMBOL_CLASS(symbol) (symbol)->aclass + #define SYMBOL_IS_ARGUMENT(symbol) (symbol)->is_argument ++#define SYMBOL_INLINED(symbol) (symbol)->is_inlined + #define SYMBOL_TYPE(symbol) (symbol)->type + #define SYMBOL_LINE(symbol) (symbol)->line + #define SYMBOL_SYMTAB(symbol) (symbol)->symtab +Index: gdb-6.8.50.20090228/gdb/testsuite/gdb.base/break.exp +=================================================================== +--- gdb-6.8.50.20090228.orig/gdb/testsuite/gdb.base/break.exp 2009-01-19 20:05:01.000000000 +0100 ++++ gdb-6.8.50.20090228/gdb/testsuite/gdb.base/break.exp 2009-03-02 01:04:45.000000000 +0100 +@@ -880,6 +880,13 @@ gdb_expect { + # marker4() is defined at line 46 when compiled with -DPROTOTYPES + pass "run until breakpoint set at small function, optimized file (line bp_location14)" + } ++ -re "Breakpoint $decimal, factorial \\(.*\\) .*\{\r\n$gdb_prompt" { ++ # GCC 4.3 emits bad line number information - see gcc/36748. ++ if { [test_compiler_info "gcc-4-3-*"] } { ++ setup_xfail *-*-* ++ } ++ fail "run until breakpoint set at small function, optimized file" ++ } + -re ".*$gdb_prompt " { + fail "run until breakpoint set at small function, optimized file" + } +Index: gdb-6.8.50.20090228/gdb/testsuite/gdb.cp/annota2.exp +=================================================================== +--- gdb-6.8.50.20090228.orig/gdb/testsuite/gdb.cp/annota2.exp 2009-01-03 06:58:04.000000000 +0100 ++++ gdb-6.8.50.20090228/gdb/testsuite/gdb.cp/annota2.exp 2009-03-02 01:04:45.000000000 +0100 +@@ -119,10 +119,11 @@ gdb_expect { + # continue until exit + # this will test: + # annotate-exited ++# `a.x is 1' is asynchronous regarding to `frames-invalid'. + # + send_gdb "continue\n" + gdb_expect { +- -re "\r\n\032\032post-prompt\r\nContinuing.\r\n\r\n\032\032starting\r\n\r\n\032\032frames-invalid\r\na.x is 1\r\n\r\n\032\032exited 0\r\n\r\nProgram exited normally.\r\n\r\n\032\032stopped\r\n$gdb_prompt$" \ ++ -re "\r\n\032\032post-prompt\r\nContinuing.\r\n\r\n\032\032starting\r\n(\r\n\032\032frames-invalid\r\n)*a.x is 1\r\n(\r\n\032\032frames-invalid\r\n)*\r\n\032\032exited 0\r\n\r\nProgram exited normally.\r\n\r\n\032\032stopped\r\n$gdb_prompt$" \ + { pass "continue until exit" } + -re ".*$gdb_prompt$" { fail "continue to exit" } + timeout { fail "continue to exit (timeout)" } +Index: gdb-6.8.50.20090228/gdb/testsuite/gdb.opt/inline-bt.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8.50.20090228/gdb/testsuite/gdb.opt/inline-bt.c 2009-03-02 01:04:45.000000000 +0100 +@@ -0,0 +1,47 @@ ++/* Copyright (C) 2008 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++int x, y; ++volatile int result; ++ ++void bar(void); ++ ++inline int func1(void) ++{ ++ bar (); ++ return x * y; ++} ++ ++inline int func2(void) ++{ ++ return x * func1 (); ++} ++ ++int main (void) ++{ ++ int val; ++ ++ x = 7; ++ y = 8; ++ bar (); ++ ++ val = func1 (); ++ result = val; ++ ++ val = func2 (); ++ result = val; ++ ++ return 0; ++} +Index: gdb-6.8.50.20090228/gdb/testsuite/gdb.opt/inline-bt.exp +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8.50.20090228/gdb/testsuite/gdb.opt/inline-bt.exp 2009-03-02 01:04:45.000000000 +0100 +@@ -0,0 +1,63 @@ ++# Copyright 2008 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++set testfile "inline-bt" ++set srcfile ${testfile}.c ++set srcfile2 "inline-markers.c" ++set fullsrcfile "${srcdir}/${subdir}/${srcfile}" ++set fullsrcfile2 "${srcdir}/${subdir}/${srcfile2}" ++set sources [list ${fullsrcfile} ${fullsrcfile2}] ++set binfile ${objdir}/${subdir}/${testfile} ++ ++if { [gdb_compile ${sources} ${binfile} \ ++ executable {debug optimize=-O2}] != "" } { ++ untested inline-bt.exp ++ return -1 ++} ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++runto_main ++ ++get_compiler_info $binfile ++get_debug_format ++if { [skip_inline_frame_tests] } { ++ untested inline-bt.exp ++ return ++} ++ ++set line1 [gdb_get_line_number "set breakpoint 1 here" ${fullsrcfile2}] ++gdb_breakpoint $srcfile2:$line1 ++ ++gdb_test "continue" ".*set breakpoint 1 here.*" "continue to bar (1)" ++gdb_test "backtrace" "#0 bar.*#1 .*main.*" "backtrace from bar (1)" ++gdb_test "info frame" ".*called by frame.*" "bar not inlined" ++ ++gdb_test "continue" ".*set breakpoint 1 here.*" "continue to bar (2)" ++gdb_test "backtrace" "#0 bar.*#1 .*func1.*#2 .*main.*" \ ++ "backtrace from bar (2)" ++gdb_test "up" "#1 .*func1.*" "up from bar (2)" ++gdb_test "info frame" ".*inlined into frame.*" "func1 inlined (2)" ++ ++gdb_test "continue" ".*set breakpoint 1 here.*" "continue to bar (3)" ++gdb_test "backtrace" "#0 bar.*#1 .*func1.*#2 .*func2.*#3 .*main.*" \ ++ "backtrace from bar (3)" ++gdb_test "up" "#1 .*func1.*" "up from bar (3)" ++gdb_test "info frame" ".*inlined into frame.*" "func1 inlined (3)" ++gdb_test "up" "#2 .*func2.*" "up from func1 (3)" ++gdb_test "info frame" ".*inlined into frame.*" "func2 inlined (3)" +Index: gdb-6.8.50.20090228/gdb/testsuite/gdb.opt/inline-cmds.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8.50.20090228/gdb/testsuite/gdb.opt/inline-cmds.c 2009-03-02 01:04:45.000000000 +0100 +@@ -0,0 +1,85 @@ ++/* Copyright (C) 2008 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++int x, y; ++volatile int result; ++ ++void bar(void); ++void marker(void); ++void noinline(void); ++ ++inline int func1(void) ++{ ++ bar (); ++ return x * y; ++} ++ ++inline int func2(void) ++{ ++ return x * func1 (); ++} ++ ++inline void func3(void) ++{ ++ bar (); ++} ++ ++inline void outer_inline1(void) ++{ ++ noinline (); ++} ++ ++inline void outer_inline2(void) ++{ ++ outer_inline1 (); ++} ++ ++int main (void) ++{ /* start of main */ ++ int val; ++ ++ x = 7; ++ y = 8; ++ ++ result = func1 (); ++ result = func2 (); ++ marker (); ++ ++ result = 0; ++ result = 0; /* set breakpoint 3 here */ ++ ++ func1 (); /* first call */ ++ func1 (); /* second call */ ++ marker (); ++ ++ result = 0; ++ result = 0; /* set breakpoint 4 here */ ++ ++ func1 (); ++ func3 (); ++ marker (); ++ ++ result = 0; ++ result = 0; /* set breakpoint 5 here */ ++ ++ marker (); ++ func1 (); ++ func3 (); ++ marker (); /* set breakpoint 6 here */ ++ ++ outer_inline2 (); ++ ++ return 0; ++} +Index: gdb-6.8.50.20090228/gdb/testsuite/gdb.opt/inline-cmds.exp +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8.50.20090228/gdb/testsuite/gdb.opt/inline-cmds.exp 2009-03-02 01:04:45.000000000 +0100 +@@ -0,0 +1,279 @@ ++# Copyright 2008 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++set testfile "inline-cmds" ++set srcfile "${testfile}.c" ++set srcfile2 "inline-markers.c" ++set fullsrcfile "${srcdir}/${subdir}/${srcfile}" ++set fullsrcfile2 "${srcdir}/${subdir}/${srcfile2}" ++set sources [list ${fullsrcfile} ${fullsrcfile2}] ++set binfile ${objdir}/${subdir}/${testfile} ++ ++if { [gdb_compile $sources ${binfile} \ ++ executable {debug optimize=-O2}] != "" } { ++ untested inline-cmds.exp ++ return -1 ++} ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++gdb_test "set listsize 1" "" ++ ++runto_main ++ ++get_compiler_info $binfile ++get_debug_format ++if { [skip_inline_frame_tests] } { ++ untested inline-cmds.exp ++ return ++} ++ ++# First, check that the things we expected to be inlined really were, ++# and those that shouldn't be weren't. ++set line1 [gdb_get_line_number "set breakpoint 1 here" ${fullsrcfile2}] ++gdb_breakpoint $srcfile2:$line1 ++set line2 [gdb_get_line_number "set breakpoint 2 here" ${fullsrcfile2}] ++gdb_breakpoint $srcfile2:$line2 ++ ++gdb_test "continue" ".*set breakpoint 1 here.*" "continue to bar (1)" ++gdb_test "backtrace" "#0 bar.*#1 .*func1.*#2 .*main.*" \ ++ "backtrace from bar (1)" ++gdb_test "up" "#1 .*func1.*" "up from bar (1)" ++gdb_test "info frame" ".*inlined into frame.*" "func1 inlined (1)" ++ ++gdb_test "continue" ".*set breakpoint 1 here.*" "continue to bar (2)" ++gdb_test "backtrace" "#0 bar.*#1 .*func1.*#2 .*func2.*#3 .*main.*" \ ++ "backtrace from bar (2)" ++gdb_test "up" "#1 .*func1.*" "up from bar (2)" ++gdb_test "info frame" ".*inlined into frame.*" "func1 inlined (2)" ++gdb_test "up" "#2 .*func2.*" "up from func1 (2)" ++gdb_test "info frame" ".*inlined into frame.*" "func2 inlined (2)" ++ ++gdb_test "continue" ".*set breakpoint 2 here.*" "continue to marker" ++gdb_test "backtrace" "#0 marker.*#1 .*main.*" "backtrace from marker" ++gdb_test "info frame" ".*called by frame.*" "marker not inlined" ++ ++# Next, check that we can next over inlined functions. We should not end up ++# inside any of them. ++delete_breakpoints ++runto_main ++ ++# The lines before the first inlined call. ++set first "x = 7|y = 8" ++ ++# Some extra lines that end up in our stepping due to code motion. ++set opt "start of main|result = 0" ++ ++# We start this test with a "list" instead of a "next", in case the ++# first non-prologue instruction in main comes from the inlined function. ++set msg "next over inlined functions" ++gdb_test_multiple "list" $msg { ++ -re "($first|result = func1|result = func2|$opt).*$gdb_prompt $" { ++ send_gdb "next\r" ++ exp_continue ++ } ++ -re "marker \\\(\\\);\r\n$gdb_prompt $" { ++ pass $msg ++ } ++} ++ ++# Check that when next shows the call of func1, it has not happened yet. ++runto_main ++ ++# Like the return value of gdb_test: -1 something is wrong, 0 passed, 1 failed. ++set bt_test -1 ++set x_test -1 ++ ++set msg "next past inlined func1" ++gdb_test_multiple "list" $msg { ++ -re "($first|$opt).*$gdb_prompt $" { ++ send_gdb "next\r" ++ exp_continue ++ } ++ -re "result = func1 \\\(\\\);\r\n$gdb_prompt $" { ++ # Check whether x has been set. If 0, we may be doing something ++ # else associated with this line besides the inlined call - e.g. ++ # loading the address of result. If 7, we may be at the call site. ++ # If 15, though, we are past the call and back at the store to ++ # result - that's bad, we should have stepped out of func1 and ++ # kept stepping until the line changed. ++ set x_val -1 ++ gdb_test_multiple "print x" "" { ++ -re "\\\$$decimal = (\[0-9\]*)\r\n$gdb_prompt $" { ++ set x_val $expect_out(1,string) ++ } ++ -re "$gdb_prompt $" { } ++ } ++ if { $x_val == 0 || $x_val == 7 } { ++ if { $x_test != 1 } { ++ set x_test 0 ++ } ++ } else { ++ set x_test 1 ++ } ++ ++ # func1 should not show up on backtraces yet. ++ if { $bt_test != 1 } { ++ set bt_test [gdb_test "backtrace" "#0 \[^#]*main.*" ""] ++ } ++ ++ send_gdb "next\r" ++ exp_continue ++ } ++ ++ -re "result = func2 \\\(\\\);\r\n$gdb_prompt $" { ++ pass $msg ++ } ++} ++ ++if { $x_test == 0 } { ++ pass "print x before func1" ++} else { ++ fail "print x before func1" ++} ++ ++if { $bt_test == 0 } { ++ pass "backtrace does not include func1" ++} else { ++ fail "backtrace does not include func1" ++} ++ ++# Next, check that we can single step into inlined functions. We should always ++# "stop" at the call sites before entering them. ++runto_main ++ ++set msg "step into func1" ++set saw_call_site 0 ++gdb_test_multiple "list" $msg { ++ -re "($first|$opt).*$gdb_prompt $" { ++ send_gdb "step\r" ++ exp_continue ++ } ++ -re "result = func1.*$gdb_prompt $" { ++ set saw_call_site 1 ++ send_gdb "step\r" ++ exp_continue ++ } ++ -re "func1 \\\(\\\) at .*\r\n$decimal.*bar \\\(\\\);\r\n$gdb_prompt $" { ++ if { $saw_call_site } { ++ pass $msg ++ } else { ++ fail $msg ++ } ++ } ++} ++ ++# Check finish out of an inlined function. ++set msg "finish from func1" ++gdb_test_multiple "finish" $msg { ++ -re "result = func1 \\\(\\\);\r\n$gdb_prompt $" { ++ pass $msg ++ } ++ -re "($first|$opt).*$gdb_prompt $" { ++ # Whoops. We finished, but ended up back at an earlier line. Keep ++ # trying. ++ send_gdb "step\r" ++ exp_continue ++ } ++ -re "func1 \\\(\\\) at .*\r\n$decimal.*bar \\\(\\\);\r\n$gdb_prompt $" { ++ send_gdb "finish\r" ++ exp_continue ++ } ++} ++ ++# Test some corner cases involving consecutive inlined functions. ++set line3 [gdb_get_line_number "set breakpoint 3 here"] ++gdb_breakpoint $line3 ++gdb_continue_to_breakpoint "consecutive func1" ++ ++gdb_test "next" ".*func1 .*first call.*" "next to first func1" ++set msg "next to second func1" ++gdb_test_multiple "next" $msg { ++ -re ".*func1 .*second call.*$gdb_prompt $" { ++ pass $msg ++ } ++ -re ".*marker .*$gdb_prompt $" { ++ # This assembles to two consecutive call instructions. ++ # Both appear to be at the same line, because they're ++ # in the body of the same inlined function. This is ++ # reasonable for the line table. GDB should take the ++ # containing block and/or function into account when ++ # deciding how far to step. The single line table entry ++ # is actually two consecutive instances of the same line. ++ kfail gdb/NNNN $msg ++ } ++} ++ ++# It is easier when the two inlined functions are not on the same line. ++set line4 [gdb_get_line_number "set breakpoint 4 here"] ++gdb_breakpoint $line4 ++gdb_continue_to_breakpoint "func1 then func3" ++ ++gdb_test "next" ".*func1 \\\(\\\);" "next to func1 before func3" ++gdb_test "next" ".*func3 \\\(\\\);" "next to func3" ++ ++# Test finishing out of one thing and into another. ++set line5 [gdb_get_line_number "set breakpoint 5 here"] ++gdb_breakpoint $line5 ++gdb_continue_to_breakpoint "finish into func1" ++ ++gdb_test "next" ".*marker \\\(\\\);" "next to finish marker" ++gdb_test "step" ".*set breakpoint 2 here.*" "step into finish marker" ++gdb_test "finish" "func1 \\\(\\\);" "finish from marker to func1" ++ ++gdb_test "step" "bar \\\(\\\);" "step into func1 for finish" ++gdb_test "finish" "func3 \\\(\\\);" "finish from func1 to func3" ++ ++# Test a deeper call stack. ++set line6 [gdb_get_line_number "set breakpoint 6 here"] ++gdb_breakpoint $line6 ++gdb_continue_to_breakpoint "before the outer_inline call" ++gdb_test "step" "marker \\\(\\\) at .*" "reach 1 the outer_inline call" ++gdb_test "finish" "main \\\(\\\) at .*outer_inline2 \\\(\\\);" "reach outer_inline2" ++gdb_test "bt" "#0 main.*" "backtrace at main of outer_inline" ++gdb_test "step" "outer_inline2 \\\(\\\) at .*" "enter outer_inline2" ++gdb_test "bt" "#0 outer_inline2.*#1 main.*" "backtrace at outer_inline2" ++gdb_test "step" "outer_inline1 \\\(\\\) at .*" "enter outer_inline1 from outer_inline2" ++ ++set msg "backtrace at outer_inline1" ++gdb_test_multiple "bt" $msg { ++ -re "#0 outer_inline1.*#1 outer_inline2.*#2 main.*$gdb_prompt $" { ++ pass $msg ++ } ++ -re "#0 $hex in outer_inline1.*#1 outer_inline2.*#2 main.*$gdb_prompt $" { ++ # Binutils PR gas/6717. Gas moves .loc past .p2align and the ++ # leading nop of the inlined call appears to be on the same line ++ # as main's call to marker. ++ xfail $msg ++ gdb_test "step" "noinline \\\(\\\);" "step to call of noinline" ++ } ++} ++ ++gdb_test "step" "noinline \\\(\\\) at .*" "enter noinline from outer_inline1" ++gdb_test "bt" "#0 noinline.*#1 .*outer_inline1.*#2 .*outer_inline2.*#3 main.*" "backtrace at noinline from outer_inline1" ++gdb_test "step" "inlined_fn \\\(\\\) at .*" "enter inlined_fn from noinline" ++gdb_test "bt" "#0 inlined_fn.*#1 noinline.*#2 .*outer_inline1.*#3 .*outer_inline2.*#4 main.*" "backtrace at inlined_fn from noinline" ++gdb_test "info frame" ".*inlined into frame.*" "inlined_fn from noinline inlined" ++gdb_test "up" "#1 noinline.*" "up to noinline" ++gdb_test "info frame" ".*\n called by frame.*" "noinline from outer_inline1 not inlined" ++gdb_test "up" "#2 .*outer_inline1.*" "up to outer_inline1" ++gdb_test "info frame" ".*inlined into frame.*" "outer_inline1 inlined" ++gdb_test "up" "#3 .*outer_inline2.*" "up to outer_inline2" ++gdb_test "info frame" ".*inlined into frame.*" "outer_inline2 inlined" ++gdb_test "up" "#4 main.*" "up from outer_inline2" ++gdb_test "info frame" ".*\n caller of frame.*" "main not inlined" +Index: gdb-6.8.50.20090228/gdb/testsuite/gdb.opt/inline-locals.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8.50.20090228/gdb/testsuite/gdb.opt/inline-locals.c 2009-03-02 01:04:45.000000000 +0100 +@@ -0,0 +1,52 @@ ++/* Copyright (C) 2008 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++int x, y; ++volatile int result; ++volatile int *array_p; ++ ++void bar(void); ++ ++inline int func1(int arg1) ++{ ++ int array[64]; ++ array_p = array; ++ array[0] = result; ++ array[1] = arg1; ++ bar (); ++ return x * y + array_p[0] * arg1; ++} ++ ++inline int func2(int arg2) ++{ ++ return x * func1 (arg2); ++} ++ ++int main (void) ++{ ++ int val; ++ ++ x = 7; ++ y = 8; ++ bar (); ++ ++ val = func1 (result); ++ result = val; ++ ++ val = func2 (result); ++ result = val; ++ ++ return 0; ++} +Index: gdb-6.8.50.20090228/gdb/testsuite/gdb.opt/inline-locals.exp +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8.50.20090228/gdb/testsuite/gdb.opt/inline-locals.exp 2009-03-02 01:04:45.000000000 +0100 +@@ -0,0 +1,118 @@ ++# Copyright 2008 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++set testfile "inline-locals" ++set srcfile ${testfile}.c ++set srcfile2 "inline-markers.c" ++set fullsrcfile "${srcdir}/${subdir}/${srcfile}" ++set fullsrcfile2 "${srcdir}/${subdir}/${srcfile2}" ++set sources [list ${fullsrcfile} ${fullsrcfile2}] ++set binfile ${objdir}/${subdir}/${testfile} ++ ++if { [gdb_compile ${sources} ${binfile} \ ++ executable {debug optimize=-O2}] != "" } { ++ untested inline-locals.exp ++ return -1 ++} ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++runto_main ++ ++get_compiler_info $binfile ++get_debug_format ++if { [skip_inline_var_tests] } { ++ untested inline-bt.exp ++ return ++} ++ ++set no_frames [skip_inline_frame_tests] ++ ++set line1 [gdb_get_line_number "set breakpoint 1 here" ${fullsrcfile2}] ++gdb_breakpoint $srcfile2:$line1 ++ ++gdb_test "continue" ".*set breakpoint 1 here.*" "continue to bar (1)" ++ ++gdb_test "continue" ".*set breakpoint 1 here.*" "continue to bar (2)" ++ ++if { ! $no_frames } { ++ gdb_test "backtrace" "#0 bar.*#1 .*func1.*#2 .*main.*" \ ++ "backtrace from bar (2)" ++ gdb_test "up" "#1 .*func1 .* at .*" "up from bar (2)" ++ gdb_test "info frame" ".*inlined into frame.*" "func1 inlined (2)" ++ gdb_test "info locals" "array = {.*}" "info locals above bar (2)" ++ ++ set msg "info args above bar (2)" ++ gdb_test_multiple "info args" $msg { ++ -re "arg1 = $decimal\r\n$gdb_prompt $" { ++ pass $msg ++ } ++ -re "arg1 = \r\n$gdb_prompt $" { ++ # GCC 4.3 loses location information for arg1. GCC 4.2 is OK. ++ if { [test_compiler_info "gcc-4-3-*"] } { ++ setup_xfail *-*-* ++ } ++ fail $msg ++ } ++ } ++} else { ++ gdb_test "up" "#1 .*main .* at .*" "up from bar (2)" ++ gdb_test "info locals" ".*arg1 = 0.*" "info locals above bar (2)" ++} ++ ++# Make sure that locals on the stack are found. This is an array to ++# prevent it from living in a register. ++gdb_test "print array\[0\]" "\\\$$decimal = 0" "print local (2)" ++ ++if { ! $no_frames } { ++ # Verify that we do not print out variables from the inlined ++ # function's caller. ++ gdb_test "print val" "No symbol \"val\" in current context\\." \ ++ "print out of scope local" ++} ++ ++# Repeat the tests from a depth of two inlined functions, and with a ++# more interesting value in the local array. ++gdb_test "continue" ".*set breakpoint 1 here.*" "continue to bar (3)" ++if { ! $no_frames } { ++ gdb_test "backtrace" "#0 bar.*#1 .*func1.*#2 .*func2.*#3 .*main.*" \ ++ "backtrace from bar (3)" ++ gdb_test "up" "#1 .*func1 .* at .*" "up from bar (3)" ++ gdb_test "info frame" ".*inlined into frame.*" "func1 inlined (3)" ++ gdb_test "info locals" "array = {.*}" "info locals above bar (3)" ++ ++ set msg "info args above bar (3)" ++ gdb_test_multiple "info args" $msg { ++ -re "arg1 = $decimal\r\n$gdb_prompt $" { ++ pass $msg ++ } ++ -re "arg1 = \r\n$gdb_prompt $" { ++ # GCC 4.3 loses location information for arg1. GCC 4.2 is OK. ++ if { [test_compiler_info "gcc-4-3-*"] } { ++ setup_xfail *-*-* ++ } ++ fail $msg ++ } ++ } ++} else { ++ gdb_test "up" "#1 .*main .* at .*" "up from bar (3)" ++ gdb_test "info locals" ".*arg1 = 1.*" "info locals above bar (3a)" ++ gdb_test "info locals" ".*arg2 = 184.*" "info locals above bar (3b)" ++} ++ ++gdb_test "print array\[0\]" "\\\$$decimal = 184" "print local (3)" +Index: gdb-6.8.50.20090228/gdb/testsuite/gdb.opt/inline-markers.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-6.8.50.20090228/gdb/testsuite/gdb.opt/inline-markers.c 2009-03-02 01:04:45.000000000 +0100 +@@ -0,0 +1,36 @@ ++/* Copyright (C) 2008 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++extern int x, y; ++ ++void bar(void) ++{ ++ x += y; /* set breakpoint 1 here */ ++} ++ ++void marker(void) ++{ ++ x += y; /* set breakpoint 2 here */ ++} ++ ++inline void inlined_fn(void) ++{ ++ x += y; ++} ++ ++void noinline(void) ++{ ++ inlined_fn (); /* inlined */ ++} +Index: gdb-6.8.50.20090228/gdb/testsuite/lib/gdb.exp +=================================================================== +--- gdb-6.8.50.20090228.orig/gdb/testsuite/lib/gdb.exp 2009-03-02 01:04:32.000000000 +0100 ++++ gdb-6.8.50.20090228/gdb/testsuite/lib/gdb.exp 2009-03-02 01:04:45.000000000 +0100 +@@ -1474,6 +1474,37 @@ proc skip_hp_tests {} { + return $skip_hp + } + ++# Return whether we should skip tests for showing inlined functions in ++# backtraces. Requires get_compiler_info and get_debug_format. ++ ++proc skip_inline_frame_tests {} { ++ # GDB only recognizes inlining information in DWARF 2 (DWARF 3). ++ if { ! [test_debug_format "DWARF 2"] } { ++ return 1 ++ } ++ ++ # GCC before 4.1 does not emit DW_AT_call_file / DW_AT_call_line. ++ if { ([test_compiler_info "gcc-2-*"] ++ || [test_compiler_info "gcc-3-*"] ++ || [test_compiler_info "gcc-4-0-*"]) } { ++ return 1 ++ } ++ ++ return 0 ++} ++ ++# Return whether we should skip tests for showing variables from ++# inlined functions. Requires get_compiler_info and get_debug_format. ++ ++proc skip_inline_var_tests {} { ++ # GDB only recognizes inlining information in DWARF 2 (DWARF 3). ++ if { ! [test_debug_format "DWARF 2"] } { ++ return 1 ++ } ++ ++ return 0 ++} ++ + set compiler_info "unknown" + set gcc_compiled 0 + set hp_cc_compiler 0 +Index: gdb-6.8.50.20090228/gdb/valops.c +=================================================================== +--- gdb-6.8.50.20090228.orig/gdb/valops.c 2009-03-02 01:01:17.000000000 +0100 ++++ gdb-6.8.50.20090228/gdb/valops.c 2009-03-02 01:04:45.000000000 +0100 +@@ -1072,7 +1072,7 @@ value_of_variable (struct symbol *var, s + frame = block_innermost_frame (b); + if (!frame) + { +- if (BLOCK_FUNCTION (b) ++ if (BLOCK_FUNCTION (b) && !block_inlined_p (b) + && SYMBOL_PRINT_NAME (BLOCK_FUNCTION (b))) + error (_("No frame is currently executing in block %s."), + SYMBOL_PRINT_NAME (BLOCK_FUNCTION (b))); +Index: gdb-6.8.50.20090228/gdb/Makefile.in +=================================================================== +--- gdb-6.8.50.20090228.orig/gdb/Makefile.in 2009-03-02 01:04:32.000000000 +0100 ++++ gdb-6.8.50.20090228/gdb/Makefile.in 2009-03-02 01:04:45.000000000 +0100 +@@ -665,6 +665,7 @@ SFILES = ada-exp.y ada-lang.c ada-typepr + inf-loop.c \ + infcall.c \ + infcmd.c inflow.c infrun.c \ ++ inline-frame.c \ + interps.c \ + jv-exp.y jv-lang.c jv-valprint.c jv-typeprint.c \ + language.c linespec.c \ +@@ -837,6 +838,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $ + user-regs.o \ + frame.o frame-unwind.o doublest.o \ + frame-base.o \ ++ inline-frame.o \ + gnu-v2-abi.o gnu-v3-abi.o cp-abi.o cp-support.o \ + cp-namespace.o \ + reggroups.o regset.o \ +Index: gdb-6.8.50.20090228/gdb/testsuite/gdb.opt/Makefile.in +=================================================================== +--- gdb-6.8.50.20090228.orig/gdb/testsuite/gdb.opt/Makefile.in 2008-04-18 01:06:54.000000000 +0200 ++++ gdb-6.8.50.20090228/gdb/testsuite/gdb.opt/Makefile.in 2009-03-02 01:04:45.000000000 +0100 +@@ -1,7 +1,7 @@ + VPATH = @srcdir@ + srcdir = @srcdir@ + +-EXECUTABLES = hello/hello ++EXECUTABLES = clobbered-registers-O2 inline-bt inline-cmds inline-locals + + MISCELLANEOUS = + diff --git a/gdb-6.8-quit-never-aborts.patch b/gdb-6.8-quit-never-aborts.patch new file mode 100644 index 0000000..ed22d6b --- /dev/null +++ b/gdb-6.8-quit-never-aborts.patch @@ -0,0 +1,72 @@ +We may abort the process of detaching threads with multiple SIGINTs - which are +being sent during a testcase terminating its child GDB. + +Some of the threads may not be properly PTRACE_DETACHed which hurts if they +should have been detached with SIGSTOP (as they are accidentally left running +on the debugger termination). + +Index: gdb-6.8.50.20081128/gdb/defs.h +=================================================================== +--- gdb-6.8.50.20081128.orig/gdb/defs.h 2008-11-27 10:23:01.000000000 +0100 ++++ gdb-6.8.50.20081128/gdb/defs.h 2008-12-06 21:49:32.000000000 +0100 +@@ -155,6 +155,7 @@ extern char *gdb_sysroot; + extern char *debug_file_directory; + + extern int quit_flag; ++extern int quit_flag_cleanup; + extern int immediate_quit; + extern int sevenbit_strings; + +@@ -168,7 +169,7 @@ extern void quit (void); + needed. */ + + #define QUIT { \ +- if (quit_flag) quit (); \ ++ if (quit_flag && !quit_flag_cleanup) quit (); \ + if (deprecated_interactive_hook) deprecated_interactive_hook (); \ + } + +Index: gdb-6.8.50.20081128/gdb/event-top.c +=================================================================== +--- gdb-6.8.50.20081128.orig/gdb/event-top.c 2008-12-04 10:34:31.000000000 +0100 ++++ gdb-6.8.50.20081128/gdb/event-top.c 2008-12-06 21:49:07.000000000 +0100 +@@ -939,7 +939,7 @@ async_request_quit (gdb_client_data arg) + is no reason to call quit again here, unless immediate_quit is + set.*/ + +- if (quit_flag || immediate_quit) ++ if ((quit_flag || immediate_quit) && !quit_flag_cleanup) + quit (); + } + +Index: gdb-6.8.50.20081128/gdb/top.c +=================================================================== +--- gdb-6.8.50.20081128.orig/gdb/top.c 2008-12-04 10:23:12.000000000 +0100 ++++ gdb-6.8.50.20081128/gdb/top.c 2008-12-06 21:49:07.000000000 +0100 +@@ -1299,7 +1299,9 @@ quit_force (char *args, int from_tty) + qt.args = args; + qt.from_tty = from_tty; + +- /* We want to handle any quit errors and exit regardless. */ ++ /* We want to handle any quit errors and exit regardless but we should never ++ get user-interrupted to properly detach the inferior. */ ++ quit_flag_cleanup = 1; + catch_errors (quit_target, &qt, + "Quitting: ", RETURN_MASK_ALL); + +Index: gdb-6.8.50.20081128/gdb/utils.c +=================================================================== +--- gdb-6.8.50.20081128.orig/gdb/utils.c 2008-12-04 10:31:00.000000000 +0100 ++++ gdb-6.8.50.20081128/gdb/utils.c 2008-12-06 21:49:07.000000000 +0100 +@@ -114,6 +114,11 @@ int job_control; + + int quit_flag; + ++/* Nonzero means we are already processing the quitting cleanups and we should ++ no longer get aborted. */ ++ ++int quit_flag_cleanup; ++ + /* Nonzero means quit immediately if Control-C is typed now, rather + than waiting until QUIT is executed. Be careful in setting this; + code which executes with immediate_quit set has to be very careful diff --git a/gdb-6.8-sparc64-silence-memcpy-check.patch b/gdb-6.8-sparc64-silence-memcpy-check.patch new file mode 100644 index 0000000..a9d30ce --- /dev/null +++ b/gdb-6.8-sparc64-silence-memcpy-check.patch @@ -0,0 +1,11 @@ +diff -up gdb-6.8/gdb/sparc-tdep.c.BAD gdb-6.8/gdb/sparc-tdep.c +--- gdb-6.8/gdb/sparc-tdep.c.BAD 2008-05-15 16:12:58.000000000 -0500 ++++ gdb-6.8/gdb/sparc-tdep.c 2008-05-15 16:13:41.000000000 -0500 +@@ -1122,6 +1122,7 @@ sparc32_store_return_value (struct type + if (sparc_floating_p (type)) + { + /* Floating return values. */ ++ len = (len <= 8) ? len : 8; + memcpy (buf, valbuf, len); + regcache_cooked_write (regcache, SPARC_F0_REGNUM, buf); + if (len > 4) diff --git a/gdb-6.8-tui-singlebinary.patch b/gdb-6.8-tui-singlebinary.patch new file mode 100644 index 0000000..cb0be45 --- /dev/null +++ b/gdb-6.8-tui-singlebinary.patch @@ -0,0 +1,24 @@ +Provide `gdb --tui' functionality for the hardlink `gdbtui'. + +--- ./gdb/gdb.c 1 Jan 2008 22:53:09 -0000 1.6 ++++ ./gdb/gdb.c 20 Jun 2008 08:02:57 -0000 +@@ -30,5 +30,19 @@ main (int argc, char **argv) + args.argv = argv; + args.use_windows = 0; + args.interpreter_p = INTERP_CONSOLE; ++ ++ if (argv[0]) ++ { ++ char *s; ++ ++ s = strrchr (argv[0], '/'); ++ if (s) ++ s++; ++ else ++ s = argv[0]; ++ if (strcmp (s, "gdbtui") == 0) ++ args.interpreter_p = INTERP_TUI; ++ } ++ + return gdb_main (&args); + } diff --git a/gdb-6.8-watchpoint-conditionals-test.patch b/gdb-6.8-watchpoint-conditionals-test.patch new file mode 100644 index 0000000..b014074 --- /dev/null +++ b/gdb-6.8-watchpoint-conditionals-test.patch @@ -0,0 +1,78 @@ +For: +http://sourceware.org/ml/gdb-patches/2008-04/msg00379.html +http://sourceware.org/ml/gdb-cvs/2008-04/msg00104.html + +--- /dev/null 2008-11-04 06:31:10.599601840 +0100 ++++ gdb-6.8/gdb/testsuite/gdb.base/watchpoint-cond.exp 2008-11-04 06:43:29.000000000 +0100 +@@ -0,0 +1,37 @@ ++# Copyright 2008 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++set testfile watchpoint-cond ++set srcfile ${testfile}.c ++set binfile ${objdir}/${subdir}/${testfile} ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { ++ untested "Couldn't compile test program" ++ return -1 ++} ++ ++# Get things started. ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++if { [runto_main] < 0 } { ++ untested watchpoint-cond ++ return -1 ++} ++ ++gdb_test "watch i if i < 20" "atchpoint \[0-9\]+: i" ++gdb_test "cont" "atchpoint \[0-9\]+: i.*Old value = 20.*New value = 19.*" +--- /dev/null 2008-11-04 06:31:10.599601840 +0100 ++++ gdb-6.8/gdb/testsuite/gdb.base/watchpoint-cond.c 2008-11-04 06:42:48.000000000 +0100 +@@ -0,0 +1,31 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2008 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++ Please email any bugs, comments, and/or additions to this file to: ++ bug-gdb@prep.ai.mit.edu */ ++ ++int ++main (int argc, char **argv) ++{ ++ static int i = 0; /* `static' to start initialized. */ ++ int j = 2; ++ ++ for (j = 0; j < 30; j++) ++ i = 30 - j; ++ ++ return 0; ++} diff --git a/gdb-archer.patch b/gdb-archer.patch new file mode 100644 index 0000000..6257740 --- /dev/null +++ b/gdb-archer.patch @@ -0,0 +1,40388 @@ +http://sourceware.org/gdb/wiki/ProjectArcher +http://sourceware.org/gdb/wiki/ArcherBranchManagement + +GIT snapshot: +commit a99e30d08ade4a2df0f943b036cd653bcd12b04d + +branch `archer' - the merge of branches: +archer-jankratochvil-merge-expr + archer-keiths-expr-cumulative + (archer-swagiaal-using-directive) +archer-jankratochvil-misc +archer-jankratochvil-python + archer-jankratochvil-type-refcount + archer-tromey-python +archer-jankratochvil-vla + archer-jankratochvil-type-refcount +archer-pmuldoon-exception-rewind-master +archer-sergio-catch-syscall +archer-tromey-charset +archer-tromey-delayed-symfile + + +diff --git a/gdb/Makefile.in b/gdb/Makefile.in +index 74aa72e..c84a4ac 100644 +--- a/gdb/Makefile.in ++++ b/gdb/Makefile.in +@@ -167,11 +167,20 @@ INTL_CFLAGS = @INCINTL@ + + # Where is the ICONV library? This can be empty if libc has iconv. + LIBICONV = @LIBICONV@ ++LIBICONV_INCLUDE = @LIBICONV_INCLUDE@ ++LIBICONV_LIBDIR = @LIBICONV_LIBDIR@ + + # Did the user give us a --with-sysroot option? + TARGET_SYSTEM_ROOT = @TARGET_SYSTEM_ROOT@ + TARGET_SYSTEM_ROOT_DEFINE = @TARGET_SYSTEM_ROOT_DEFINE@ + ++# Did the user give us a --with-gdb-datadir option? ++GDB_DATADIR_PATH = @GDB_DATADIR_PATH@ ++ ++# The argument to --with-pythondir. If not given, this is ++# GDB_DATADIR_PATH/python. ++pythondir = @pythondir@ ++ + # Helper code from gnulib. + LIBGNU = gnulib/libgnu.a + INCGNU = -I$(srcdir)/gnulib -Ignulib +@@ -270,12 +279,34 @@ SUBDIR_TUI_CFLAGS= \ + # + SUBDIR_PYTHON_OBS = \ + python.o \ ++ python-block.o \ ++ python-breakpoint.o \ + python-cmd.o \ ++ python-frame.o \ ++ python-function.o \ ++ python-hooks.o \ ++ python-membuf.o \ ++ python-objfile.o \ ++ python-param.o \ ++ python-symbol.o \ ++ python-symtab.o \ ++ python-type.o \ + python-utils.o \ + python-value.o + SUBDIR_PYTHON_SRCS = \ + python/python.c \ ++ python/python-block.c \ ++ python/python-breakpoint.c \ + python/python-cmd.c \ ++ python/python-frame.c \ ++ python/python-function.c \ ++ python/python-hooks.c \ ++ python/python-membuf.c \ ++ python/python-objfile.c \ ++ python/python-param.c \ ++ python/python-symbol.c \ ++ python/python-symtab.c \ ++ python/python-type.c \ + python/python-utils.c \ + python/python-value.c + SUBDIR_PYTHON_DEPS = +@@ -390,7 +421,8 @@ INTERNAL_CFLAGS_BASE = \ + $(CFLAGS) $(GLOBAL_CFLAGS) $(PROFILE_CFLAGS) \ + $(GDB_CFLAGS) $(OPCODES_CFLAGS) $(READLINE_CFLAGS) \ + $(BFD_CFLAGS) $(INCLUDE_CFLAGS) $(LIBDECNUMBER_CFLAGS) \ +- $(INTL_CFLAGS) $(INCGNU) $(ENABLE_CFLAGS) $(INTERNAL_CPPFLAGS) ++ $(INTL_CFLAGS) $(INCGNU) $(ENABLE_CFLAGS) $(INTERNAL_CPPFLAGS) \ ++ $(LIBICONV_INCLUDE) + INTERNAL_WARN_CFLAGS = $(INTERNAL_CFLAGS_BASE) $(GDB_WARN_CFLAGS) + INTERNAL_CFLAGS = $(INTERNAL_WARN_CFLAGS) $(GDB_WERROR_CFLAGS) + +@@ -402,7 +434,7 @@ LDFLAGS = @LDFLAGS@ + # I think it's perfectly reasonable for a user to set -pg in CFLAGS + # and have it work; that's why CFLAGS is here. + # PROFILE_CFLAGS is _not_ included, however, because we use monstartup. +-INTERNAL_LDFLAGS = $(CFLAGS) $(GLOBAL_CFLAGS) $(MH_LDFLAGS) $(LDFLAGS) $(CONFIG_LDFLAGS) ++INTERNAL_LDFLAGS = $(CFLAGS) $(GLOBAL_CFLAGS) $(MH_LDFLAGS) $(LDFLAGS) $(CONFIG_LDFLAGS) $(LIBICONV_LIBDIR) + + # If your system is missing alloca(), or, more likely, it's there but + # it doesn't work, then refer to libiberty. +@@ -663,6 +695,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \ + valarith.c valops.c valprint.c value.c varobj.c vec.c \ + wrapper.c \ + xml-tdesc.c xml-support.c \ ++ xml-syscall.c \ + inferior.c + + LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c +@@ -733,7 +766,8 @@ config/sparc/nm-sol2.h config/nm-linux.h config/mips/nm-irix5.h \ + config/rs6000/nm-rs6000.h top.h bsd-kvm.h gdb-stabs.h reggroups.h \ + annotate.h sim-regno.h dictionary.h dfp.h main.h frame-unwind.h \ + remote-fileio.h i386-linux-tdep.h vax-tdep.h objc-lang.h \ +-sentinel-frame.h bcache.h symfile.h windows-tdep.h linux-tdep.h ++sentinel-frame.h bcache.h symfile.h windows-tdep.h linux-tdep.h xml-syscall.h \ ++python/python.h python/python-internal.h + + # Header files that already have srcdir in them, or which are in objdir. + +@@ -812,10 +846,16 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \ + trad-frame.o \ + tramp-frame.o \ + solib.o solib-null.o \ +- prologue-value.o memory-map.o xml-support.o \ ++ prologue-value.o memory-map.o xml-support.o xml-syscall.o \ + target-descriptions.o target-memory.o xml-tdesc.o xml-builtin.o \ + inferior.o osdata.o + ++# Definitions for the syscall's XML files and dir ++XML_SYSCALLS_DIR = syscalls/ ++XML_SYSCALLS_FILES = gdb-syscalls.dtd \ ++ ppc-linux.xml ppc64-linux.xml \ ++ i386-linux.xml amd64-linux.xml ++ + TSOBS = inflow.o + + SUBDIRS = @subdirs@ +@@ -849,11 +889,38 @@ generated_files = config.h observer.h observer.inc ada-lex.c \ + $(COMPILE) $< + $(POSTCOMPILE) + +-all: gdb$(EXEEXT) $(CONFIG_ALL) ++all: gdb$(EXEEXT) $(CONFIG_ALL) .gdbinit xml-syscall-copy + @$(MAKE) $(FLAGS_TO_PASS) DO=all "DODIRS=`echo $(SUBDIRS) | sed 's/testsuite//'`" subdir_do + .PHONY: all-tui + all-tui: $(TUI)$(EXEEXT) + ++xml-syscall-copy: ++ if [ "`cd $(srcdir) && pwd`" != "`pwd`" ] ; then \ ++ mkdir -p ./$(XML_SYSCALLS_DIR) ; \ ++ list='$(XML_SYSCALLS_FILES)' ; \ ++ for file in $$list ; do \ ++ f=$(srcdir)/$(XML_SYSCALLS_DIR)/$$file ; \ ++ if test -f $$f ; then \ ++ $(INSTALL_DATA) $$f \ ++ ./$(XML_SYSCALLS_DIR) ; \ ++ fi ; \ ++ done ; \ ++ fi ; ++ ++# This target is responsible for properly installing the syscalls' ++# XML files in the system. ++xml-syscall-install: ++ $(SHELL) $(srcdir)/../mkinstalldirs \ ++ $(DESTDIR)$(GDB_DATADIR_PATH)/$(XML_SYSCALLS_DIR) ; \ ++ list='$(XML_SYSCALLS_FILES)' ; \ ++ for file in $$list ; do \ ++ f=$(srcdir)/$(XML_SYSCALLS_DIR)/$$file ; \ ++ if test -f $$f ; then \ ++ $(INSTALL_DATA) $$f \ ++ $(DESTDIR)$(GDB_DATADIR_PATH)/$(XML_SYSCALLS_DIR) ; \ ++ fi ; \ ++ done ; ++ + installcheck: + + # The check target can not use subdir_do, because subdir_do does not +@@ -907,8 +974,11 @@ gdb.z:gdb.1 + # source file and doesn't care about rebuilding or just wants to save the + # time it takes for make to check that all is up to date. + # install-only is intended to address that need. +-install: all install-only +-install-only: $(CONFIG_INSTALL) ++install: all install-only ++ ++# The "install-only" target also installs the syscalls' XML files in ++# the system. ++install-only: $(CONFIG_INSTALL) xml-syscall-install + transformed_name=`t='$(program_transform_name)'; \ + echo gdb | sed -e "$$t"` ; \ + if test "x$$transformed_name" = x; then \ +@@ -1202,6 +1272,12 @@ stamp-h: config.in config.status + CONFIG_LINKS= \ + $(SHELL) config.status + ++.gdbinit: gdbinit.in config.status ++ CONFIG_FILES=".gdbinit:gdbinit.in" \ ++ CONFIG_COMMANDS= \ ++ CONFIG_HEADERS= \ ++ $(SHELL) config.status ++ + config.status: configure configure.tgt configure.host + $(SHELL) config.status --recheck + +@@ -1845,10 +1921,54 @@ python.o: $(srcdir)/python/python.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python.c + $(POSTCOMPILE) + ++python-block.o: $(srcdir)/python/python-block.c ++ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-block.c ++ $(POSTCOMPILE) ++ ++python-breakpoint.o: $(srcdir)/python/python-breakpoint.c ++ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-breakpoint.c ++ $(POSTCOMPILE) ++ + python-cmd.o: $(srcdir)/python/python-cmd.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-cmd.c + $(POSTCOMPILE) + ++python-frame.o: $(srcdir)/python/python-frame.c ++ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-frame.c ++ $(POSTCOMPILE) ++ ++python-function.o: $(srcdir)/python/python-function.c ++ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-function.c ++ $(POSTCOMPILE) ++ ++python-hooks.o: $(srcdir)/python/python-hooks.c ++ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-hooks.c ++ $(POSTCOMPILE) ++ ++python-membuf.o: $(srcdir)/python/python-membuf.c ++ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-membuf.c ++ $(POSTCOMPILE) ++ ++python-objfile.o: $(srcdir)/python/python-objfile.c ++ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-objfile.c ++ $(POSTCOMPILE) ++ ++python-param.o: $(srcdir)/python/python-param.c ++ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-param.c ++ $(POSTCOMPILE) ++ ++python-symbol.o: $(srcdir)/python/python-symbol.c ++ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-symbol.c ++ $(POSTCOMPILE) ++ ++python-symtab.o: $(srcdir)/python/python-symtab.c ++ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-symtab.c ++ $(POSTCOMPILE) ++ ++python-type.o: $(srcdir)/python/python-type.c ++ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-type.c ++ $(POSTCOMPILE) ++ + python-utils.o: $(srcdir)/python/python-utils.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-utils.c + $(POSTCOMPILE) +@@ -1857,6 +1977,38 @@ python-value.o: $(srcdir)/python/python-value.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-value.c + $(POSTCOMPILE) + ++# All python library files, with the "python/lib" stripped off. ++# Note that we should only install files in the "gdb" module. ++PY_FILES = gdb/FrameIterator.py gdb/command/alias.py \ ++ gdb/command/backtrace.py gdb/command/require.py \ ++ gdb/command/pahole.py gdb/command/__init__.py \ ++ gdb/command/ignore_errors.py gdb/command/save_breakpoints.py \ ++ gdb/libstdcxx/v6/printers.py gdb/libstdcxx/v6/__init__.py \ ++ gdb/libstdcxx/__init__.py gdb/function/caller_is.py \ ++ gdb/function/in_scope.py gdb/function/__init__.py gdb/backtrace.py \ ++ gdb/__init__.py ++ ++# Install the Python library. Python library files go under ++# $(pythondir). ++install-python: ++ files='$(PY_FILES)'; for file in $$files; do \ ++ dir=`echo "$$file" | sed 's,/[^/]*$$,,'`; \ ++ $(SHELL) $(srcdir)/../mkinstalldirs $(DESTDIR)$(pythondir)/$$dir; \ ++ $(INSTALL_DATA) $(srcdir)/python/lib/$$file $(DESTDIR)$(pythondir)/$$file; \ ++ done ++ ++# Other packages may have their files installed in $(pythondir). ++uninstall-python: ++ files='$(PY_FILES)'; for file in $$files; do \ ++ slashdir=`echo "/$$file" | sed 's,/[^/]*$$,,'`; \ ++ rm -f $(DESTDIR)$(pythondir)/$$file; \ ++ while test "x$$file" != "x$$slashdir"; do \ ++ rmdir 2>/dev/null "$(DESTDIR)$(pythondir)$$slashdir"; \ ++ file="$$slashdir"; \ ++ slashdir=`echo "$$file" | sed 's,/[^/]*$$,,'`; \ ++ done \ ++ done ++ + # + # Dependency tracking. Most of this is conditional on GNU Make being + # found by configure; if GNU Make is not found, we fall back to a +diff --git a/gdb/NEWS b/gdb/NEWS +index 9078412..3f084e7 100644 +--- a/gdb/NEWS ++++ b/gdb/NEWS +@@ -3,6 +3,13 @@ + + *** Changes since GDB 6.8 + ++* GDB now has support for multi-byte and wide character sets on the ++target. Strings whose character type is wchar_t, char16_t, or ++char32_t are now correctly printed. GDB supports wide- and unicode- ++literals in C, that is, L'x', L"string", u'x', u"string", U'x', and ++U"string" syntax. And, GDB allows the "%ls" and "%lc" formats in ++`printf'. ++ + * GDB now supports automatic retrieval of shared library files from + remote targets. To use this feature, specify a system root that begins + with the `remote:' prefix, either via the `set sysroot' command or via +@@ -182,6 +189,11 @@ set target-async + with GDB while the target is running. "show target-async" displays the + current state of asynchronous execution of the target. + ++set target-wide-charset ++show target-wide-charset ++ The target-wide-charset is the name of the character set that GDB ++ uses when printing characters whose type is wchar_t. ++ + set tcp auto-retry (on|off) + show tcp auto-retry + set tcp connect-timeout +diff --git a/gdb/acinclude.m4 b/gdb/acinclude.m4 +index 81b5d47..c2bd043 100644 +--- a/gdb/acinclude.m4 ++++ b/gdb/acinclude.m4 +@@ -29,6 +29,9 @@ sinclude([../config/depstand.m4]) + dnl For AM_LC_MESSAGES + sinclude([../config/lcmessage.m4]) + ++dnl For AM_LANGINFO_CODESET. ++sinclude([../config/codeset.m4]) ++ + # + # Sometimes the native compiler is a bogus stub for gcc or /usr/ucb/cc. This + # makes configure think it's cross compiling. If --target wasn't used, then +@@ -174,8 +177,8 @@ AC_DEFUN([AM_ICONV], + AC_ARG_WITH([libiconv-prefix], + [ --with-libiconv-prefix=DIR search for libiconv in DIR/include and DIR/lib], [ + for dir in `echo "$withval" | tr : ' '`; do +- if test -d $dir/include; then CPPFLAGS="$CPPFLAGS -I$dir/include"; fi +- if test -d $dir/lib; then LDFLAGS="$LDFLAGS -L$dir/lib"; fi ++ if test -d $dir/include; then LIBICONV_INCLUDE="-I$dir/include"; CPPFLAGS="$CPPFLAGS -I$dir/include"; fi ++ if test -d $dir/lib; then LIBICONV_LIBDIR="-L$dir/lib"; LDFLAGS="$LDFLAGS -L$dir/lib"; fi + done + ]) + +@@ -230,6 +233,8 @@ size_t iconv(); + LIBICONV="-liconv" + fi + AC_SUBST(LIBICONV) ++ AC_SUBST(LIBICONV_INCLUDE) ++ AC_SUBST(LIBICONV_LIBDIR) + ]) + + dnl written by Guido Draheim , original by Alexandre Oliva +diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c +index 671cb35..edcee3f 100644 +--- a/gdb/ada-lang.c ++++ b/gdb/ada-lang.c +@@ -486,7 +486,7 @@ coerce_unspec_val_to_type (struct value *val, struct type *type) + set_value_component_location (result, val); + set_value_bitsize (result, value_bitsize (val)); + set_value_bitpos (result, value_bitpos (val)); +- VALUE_ADDRESS (result) += value_offset (val); ++ set_value_address (result, value_address (val)); + if (value_lazy (val) + || TYPE_LENGTH (type) > TYPE_LENGTH (value_type (val))) + set_value_lazy (result, 1); +@@ -1328,7 +1328,7 @@ thin_data_pntr (struct value *val) + value_copy (val)); + else + return value_from_longest (desc_data_type (thin_descriptor_type (type)), +- VALUE_ADDRESS (val) + value_offset (val)); ++ value_address (val)); + } + + /* True iff TYPE indicates a "thick" array pointer type. */ +@@ -1393,7 +1393,7 @@ desc_bounds (struct value *arr) + if (TYPE_CODE (type) == TYPE_CODE_PTR) + addr = value_as_long (arr); + else +- addr = VALUE_ADDRESS (arr) + value_offset (arr); ++ addr = value_address (arr); + + return + value_from_longest (lookup_pointer_type (bounds_type), +@@ -1666,8 +1666,8 @@ ada_type_of_array (struct value *arr, int bounds) + return NULL; + while (arity > 0) + { +- struct type *range_type = alloc_type (objf); +- struct type *array_type = alloc_type (objf); ++ struct type *range_type = alloc_type (objf, NULL); ++ struct type *array_type = alloc_type (objf, NULL); + struct value *low = desc_one_bound (descriptor, arity, 0); + struct value *high = desc_one_bound (descriptor, arity, 1); + arity -= 1; +@@ -1774,9 +1774,9 @@ packed_array_type (struct type *type, long *elt_bits) + if (TYPE_CODE (type) != TYPE_CODE_ARRAY) + return type; + +- new_type = alloc_type (TYPE_OBJFILE (type)); + new_elt_type = packed_array_type (ada_check_typedef (TYPE_TARGET_TYPE (type)), + elt_bits); ++ new_type = alloc_type (TYPE_OBJFILE (type), new_elt_type); + create_array_type (new_type, new_elt_type, TYPE_INDEX_TYPE (type)); + TYPE_FIELD_BITSIZE (new_type, 0) = *elt_bits; + TYPE_NAME (new_type) = ada_type_name (type); +@@ -1831,6 +1831,7 @@ decode_packed_array_type (struct type *type) + return NULL; + } + shadow_type = SYMBOL_TYPE (sym); ++ CHECK_TYPEDEF (shadow_type); + + if (TYPE_CODE (shadow_type) != TYPE_CODE_ARRAY) + { +@@ -2005,10 +2006,9 @@ ada_value_primitive_packed_val (struct value *obj, const gdb_byte *valaddr, + } + else if (VALUE_LVAL (obj) == lval_memory && value_lazy (obj)) + { +- v = value_at (type, +- VALUE_ADDRESS (obj) + value_offset (obj) + offset); ++ v = value_at (type, value_address (obj) + offset); + bytes = (unsigned char *) alloca (len); +- read_memory (VALUE_ADDRESS (v), bytes, len); ++ read_memory (value_address (v), bytes, len); + } + else + { +@@ -2018,15 +2018,18 @@ ada_value_primitive_packed_val (struct value *obj, const gdb_byte *valaddr, + + if (obj != NULL) + { ++ CORE_ADDR new_addr; ++ + set_value_component_location (v, obj); +- VALUE_ADDRESS (v) += value_offset (obj) + offset; ++ new_addr = value_address (obj) + offset; + set_value_bitpos (v, bit_offset + value_bitpos (obj)); + set_value_bitsize (v, bit_size); + if (value_bitpos (v) >= HOST_CHAR_BIT) + { +- VALUE_ADDRESS (v) += 1; ++ new_addr++; + set_value_bitpos (v, value_bitpos (v) - HOST_CHAR_BIT); + } ++ set_value_address (v, new_addr); + } + else + set_value_bitsize (v, bit_size); +@@ -2218,7 +2221,7 @@ ada_value_assign (struct value *toval, struct value *fromval) + int from_size; + char *buffer = (char *) alloca (len); + struct value *val; +- CORE_ADDR to_addr = VALUE_ADDRESS (toval) + value_offset (toval); ++ CORE_ADDR to_addr = value_address (toval); + + if (TYPE_CODE (type) == TYPE_CODE_FLT) + fromval = value_cast (type, fromval); +@@ -2259,8 +2262,7 @@ value_assign_to_component (struct value *container, struct value *component, + struct value *val) + { + LONGEST offset_in_container = +- (LONGEST) (VALUE_ADDRESS (component) + value_offset (component) +- - VALUE_ADDRESS (container) - value_offset (container)); ++ (LONGEST) (value_address (component) - value_address (container)); + int bit_offset_in_container = + value_bitpos (component) - value_bitpos (container); + int bits; +@@ -3788,7 +3790,7 @@ parse_old_style_renaming (struct type *type, + /* Return an lvalue containing the value VAL. This is the identity on + lvalues, and otherwise has the side-effect of pushing a copy of VAL + on the stack, using and updating *SP as the stack pointer, and +- returning an lvalue whose VALUE_ADDRESS points to the copy. */ ++ returning an lvalue whose value_address points to the copy. */ + + static struct value * + ensure_lval (struct value *val, CORE_ADDR *sp) +@@ -3802,12 +3804,12 @@ ensure_lval (struct value *val, CORE_ADDR *sp) + indicated. */ + if (gdbarch_inner_than (current_gdbarch, 1, 2)) + { +- /* Stack grows downward. Align SP and VALUE_ADDRESS (val) after ++ /* Stack grows downward. Align SP and value_address (val) after + reserving sufficient space. */ + *sp -= len; + if (gdbarch_frame_align_p (current_gdbarch)) + *sp = gdbarch_frame_align (current_gdbarch, *sp); +- VALUE_ADDRESS (val) = *sp; ++ set_value_address (val, *sp); + } + else + { +@@ -3815,14 +3817,14 @@ ensure_lval (struct value *val, CORE_ADDR *sp) + then again, re-align the frame. */ + if (gdbarch_frame_align_p (current_gdbarch)) + *sp = gdbarch_frame_align (current_gdbarch, *sp); +- VALUE_ADDRESS (val) = *sp; ++ set_value_address (val, *sp); + *sp += len; + if (gdbarch_frame_align_p (current_gdbarch)) + *sp = gdbarch_frame_align (current_gdbarch, *sp); + } + VALUE_LVAL (val) = lval_memory; + +- write_memory (VALUE_ADDRESS (val), value_contents_raw (val), len); ++ write_memory (value_address (val), value_contents_raw (val), len); + } + + return val; +@@ -3911,12 +3913,12 @@ make_array_descriptor (struct type *type, struct value *arr, CORE_ADDR *sp) + bounds = ensure_lval (bounds, sp); + + modify_general_field (value_contents_writeable (descriptor), +- VALUE_ADDRESS (ensure_lval (arr, sp)), ++ value_address (ensure_lval (arr, sp)), + fat_pntr_data_bitpos (desc_type), + fat_pntr_data_bitsize (desc_type)); + + modify_general_field (value_contents_writeable (descriptor), +- VALUE_ADDRESS (bounds), ++ value_address (bounds), + fat_pntr_bounds_bitpos (desc_type), + fat_pntr_bounds_bitsize (desc_type)); + +@@ -6790,7 +6792,7 @@ variant_field_index (struct type *type) + static struct type * + empty_record (struct objfile *objfile) + { +- struct type *type = alloc_type (objfile); ++ struct type *type = alloc_type (objfile, NULL); + TYPE_CODE (type) = TYPE_CODE_STRUCT; + TYPE_NFIELDS (type) = 0; + TYPE_FIELDS (type) = NULL; +@@ -6847,7 +6849,7 @@ ada_template_to_fixed_record_type_1 (struct type *type, + nfields++; + } + +- rtype = alloc_type (TYPE_OBJFILE (type)); ++ rtype = alloc_type (TYPE_OBJFILE (type), NULL); + TYPE_CODE (rtype) = TYPE_CODE_STRUCT; + INIT_CPLUS_SPECIFIC (rtype); + TYPE_NFIELDS (rtype) = nfields; +@@ -7034,7 +7036,8 @@ template_to_static_fixed_type (struct type *type0) + new_type = static_unwrap_type (field_type); + if (type == type0 && new_type != field_type) + { +- TYPE_TARGET_TYPE (type0) = type = alloc_type (TYPE_OBJFILE (type0)); ++ TYPE_TARGET_TYPE (type0) = type = alloc_type (TYPE_OBJFILE (type0), ++ NULL); + TYPE_CODE (type) = TYPE_CODE (type0); + INIT_CPLUS_SPECIFIC (type); + TYPE_NFIELDS (type) = nfields; +@@ -7079,7 +7082,7 @@ to_record_with_fixed_variant_part (struct type *type, const gdb_byte *valaddr, + else + dval = dval0; + +- rtype = alloc_type (TYPE_OBJFILE (type)); ++ rtype = alloc_type (TYPE_OBJFILE (type), NULL); + TYPE_CODE (rtype) = TYPE_CODE_STRUCT; + INIT_CPLUS_SPECIFIC (rtype); + TYPE_NFIELDS (rtype) = nfields; +@@ -7251,7 +7254,7 @@ to_fixed_array_type (struct type *type0, struct value *dval, + if (elt_type0 == elt_type) + result = type0; + else +- result = create_array_type (alloc_type (TYPE_OBJFILE (type0)), ++ result = create_array_type (alloc_type (TYPE_OBJFILE (type0), NULL), + elt_type, TYPE_INDEX_TYPE (type0)); + } + else +@@ -7281,7 +7284,7 @@ to_fixed_array_type (struct type *type0, struct value *dval, + struct type *range_type = + to_fixed_range_type (TYPE_FIELD_NAME (index_type_desc, i), + dval, TYPE_OBJFILE (type0)); +- result = create_array_type (alloc_type (TYPE_OBJFILE (type0)), ++ result = create_array_type (alloc_type (TYPE_OBJFILE (type0), NULL), + result, range_type); + } + if (!ignore_too_big && TYPE_LENGTH (result) > varsize_limit) +@@ -7523,7 +7526,7 @@ static struct value * + ada_to_fixed_value (struct value *val) + { + return ada_to_fixed_value_create (value_type (val), +- VALUE_ADDRESS (val) + value_offset (val), ++ value_address (val), + val); + } + +@@ -7869,7 +7872,7 @@ unwrap_value (struct value *val) + return + coerce_unspec_val_to_type + (val, ada_to_fixed_type (raw_real_type, 0, +- VALUE_ADDRESS (val) + value_offset (val), ++ value_address (val), + NULL, 1)); + } + } +@@ -9546,7 +9549,7 @@ to_fixed_range_type (char *name, struct value *dval, struct objfile *objfile) + if (L < INT_MIN || U > INT_MAX) + return raw_type; + else +- return create_range_type (alloc_type (objfile), raw_type, ++ return create_range_type (alloc_type (objfile, NULL), raw_type, + discrete_type_low_bound (raw_type), + discrete_type_high_bound (raw_type)); + } +@@ -9611,7 +9614,7 @@ to_fixed_range_type (char *name, struct value *dval, struct objfile *objfile) + + if (objfile == NULL) + objfile = TYPE_OBJFILE (base_type); +- type = create_range_type (alloc_type (objfile), base_type, L, U); ++ type = create_range_type (alloc_type (objfile, NULL), base_type, L, U); + TYPE_NAME (type) = name; + return type; + } +@@ -11009,9 +11012,9 @@ ada_language_arch_info (struct gdbarch *gdbarch, + /* Not really used, but needed in the ada_language_defn. */ + + static void +-emit_char (int c, struct ui_file *stream, int quoter) ++emit_char (int c, struct type *type, struct ui_file *stream, int quoter) + { +- ada_emit_char (c, stream, quoter, 1); ++ ada_emit_char (c, type, stream, quoter, 1); + } + + static int +diff --git a/gdb/ada-lang.h b/gdb/ada-lang.h +index c7cc62a..fac027b 100644 +--- a/gdb/ada-lang.h ++++ b/gdb/ada-lang.h +@@ -257,12 +257,12 @@ extern int ada_value_print (struct value *, struct ui_file *, + + /* Defined in ada-lang.c */ + +-extern void ada_emit_char (int, struct ui_file *, int, int); ++extern void ada_emit_char (int, struct type *, struct ui_file *, int, int); + +-extern void ada_printchar (int, struct ui_file *); ++extern void ada_printchar (int, struct type *, struct ui_file *); + +-extern void ada_printstr (struct ui_file *, const gdb_byte *, +- unsigned int, int, int, ++extern void ada_printstr (struct ui_file *, struct type *, const gdb_byte *, ++ unsigned int, int, + const struct value_print_options *); + + struct value *ada_convert_actual (struct value *actual, +diff --git a/gdb/ada-tasks.c b/gdb/ada-tasks.c +index 61ed06e..8b1639e 100644 +--- a/gdb/ada-tasks.c ++++ b/gdb/ada-tasks.c +@@ -293,7 +293,7 @@ read_fat_string_value (char *dest, struct value *val, int max_len) + + /* Extract LEN characters from the fat string. */ + array_val = value_ind (value_field (val, array_fieldno)); +- read_memory (VALUE_ADDRESS (array_val), dest, len); ++ read_memory (value_address (array_val), dest, len); + + /* Add the NUL character to close the string. */ + dest[len] = '\0'; +diff --git a/gdb/ada-typeprint.c b/gdb/ada-typeprint.c +index f00824a..ef665c4 100644 +--- a/gdb/ada-typeprint.c ++++ b/gdb/ada-typeprint.c +@@ -357,16 +357,17 @@ print_array_type (struct type *type, struct ui_file *stream, int show, + bitsize = 0; + fprintf_filtered (stream, "array ("); + ++ if (type == NULL) ++ { ++ fprintf_filtered (stream, _("")); ++ return; ++ } ++ + n_indices = -1; + if (show < 0) + fprintf_filtered (stream, "..."); + else + { +- if (type == NULL) +- { +- fprintf_filtered (stream, _("")); +- return; +- } + if (ada_is_simple_array_type (type)) + { + struct type *range_desc_type = +diff --git a/gdb/ada-valprint.c b/gdb/ada-valprint.c +index 9647971..cfa94a2 100644 +--- a/gdb/ada-valprint.c ++++ b/gdb/ada-valprint.c +@@ -269,7 +269,8 @@ printable_val_type (struct type *type, const gdb_byte *valaddr) + (1 or 2) of the character. */ + + void +-ada_emit_char (int c, struct ui_file *stream, int quoter, int type_len) ++ada_emit_char (int c, struct type *type, struct ui_file *stream, ++ int quoter, int type_len) + { + if (type_len != 2) + type_len = 1; +@@ -366,10 +367,10 @@ ada_print_floating (const gdb_byte *valaddr, struct type *type, + } + + void +-ada_printchar (int c, struct ui_file *stream) ++ada_printchar (int c, struct type *type, struct ui_file *stream) + { + fputs_filtered ("'", stream); +- ada_emit_char (c, stream, '\'', 1); ++ ada_emit_char (c, type, stream, '\'', 1); + fputs_filtered ("'", stream); + } + +@@ -411,7 +412,7 @@ ada_print_scalar (struct type *type, LONGEST val, struct ui_file *stream) + break; + + case TYPE_CODE_CHAR: +- LA_PRINT_CHAR ((unsigned char) val, stream); ++ LA_PRINT_CHAR ((unsigned char) val, type, stream); + break; + + case TYPE_CODE_BOOL: +@@ -454,7 +455,7 @@ ada_print_scalar (struct type *type, LONGEST val, struct ui_file *stream) + */ + + static void +-printstr (struct ui_file *stream, const gdb_byte *string, ++printstr (struct ui_file *stream, struct type *elttype, const gdb_byte *string, + unsigned int length, int force_ellipses, int type_len, + const struct value_print_options *options) + { +@@ -506,7 +507,7 @@ printstr (struct ui_file *stream, const gdb_byte *string, + in_quotes = 0; + } + fputs_filtered ("'", stream); +- ada_emit_char (char_at (string, i, type_len), stream, '\'', ++ ada_emit_char (char_at (string, i, type_len), elttype, stream, '\'', + type_len); + fputs_filtered ("'", stream); + fprintf_filtered (stream, _(" "), reps); +@@ -524,7 +525,7 @@ printstr (struct ui_file *stream, const gdb_byte *string, + fputs_filtered ("\"", stream); + in_quotes = 1; + } +- ada_emit_char (char_at (string, i, type_len), stream, '"', ++ ada_emit_char (char_at (string, i, type_len), elttype, stream, '"', + type_len); + things_printed += 1; + } +@@ -544,11 +545,12 @@ printstr (struct ui_file *stream, const gdb_byte *string, + } + + void +-ada_printstr (struct ui_file *stream, const gdb_byte *string, +- unsigned int length, int width, int force_ellipses, ++ada_printstr (struct ui_file *stream, struct type *type, const gdb_byte *string, ++ unsigned int length, int force_ellipses, + const struct value_print_options *options) + { +- printstr (stream, string, length, force_ellipses, width, options); ++ printstr (stream, type, string, length, force_ellipses, TYPE_LENGTH (type), ++ options); + } + + +@@ -637,7 +639,7 @@ ada_val_print_array (struct type *type, const gdb_byte *valaddr, + len = temp_len; + } + +- printstr (stream, valaddr, len, 0, eltlen, options); ++ printstr (stream, elttype, valaddr, len, 0, eltlen, options); + result = len; + } + else +@@ -688,7 +690,7 @@ ada_val_print_1 (struct type *type, const gdb_byte *valaddr0, + } + else + retn = ada_val_print_1 (value_type (val), value_contents (val), 0, +- VALUE_ADDRESS (val), stream, recurse, options); ++ value_address (val), stream, recurse, options); + value_free_to_mark (mark); + return retn; + } +@@ -817,7 +819,7 @@ ada_val_print_1 (struct type *type, const gdb_byte *valaddr0, + { + fputs_filtered (" ", stream); + ada_printchar ((unsigned char) unpack_long (type, valaddr), +- stream); ++ type, stream); + } + } + return 0; +@@ -904,7 +906,7 @@ ada_val_print_1 (struct type *type, const gdb_byte *valaddr0, + deref_val_int)); + val_print (value_type (deref_val), + value_contents (deref_val), 0, +- VALUE_ADDRESS (deref_val), stream, recurse + 1, ++ value_address (deref_val), stream, recurse + 1, + options, current_language); + } + else +@@ -944,7 +946,7 @@ ada_value_print (struct value *val0, struct ui_file *stream, + const struct value_print_options *options) + { + const gdb_byte *valaddr = value_contents (val0); +- CORE_ADDR address = VALUE_ADDRESS (val0) + value_offset (val0); ++ CORE_ADDR address = value_address (val0); + struct type *type = + ada_to_fixed_type (value_type (val0), valaddr, address, NULL, 1); + struct value *val = +diff --git a/gdb/auxv.c b/gdb/auxv.c +index 5007cd0..241a6ac 100644 +--- a/gdb/auxv.c ++++ b/gdb/auxv.c +@@ -247,7 +247,8 @@ fprint_target_auxv (struct ui_file *file, struct target_ops *ops) + get_user_print_options (&opts); + if (opts.addressprint) + fprintf_filtered (file, "0x%s", paddr_nz (val)); +- val_print_string (val, -1, 1, file, &opts); ++ val_print_string (builtin_type (target_gdbarch)->builtin_char, ++ val, -1, file, &opts); + fprintf_filtered (file, "\n"); + } + break; +diff --git a/gdb/block.c b/gdb/block.c +index 8f0140c..d451769 100644 +--- a/gdb/block.c ++++ b/gdb/block.c +@@ -207,24 +207,16 @@ block_set_scope (struct block *block, const char *scope, + } + + /* This returns the first using directives associated to BLOCK, if +- any. */ +- +-/* FIXME: carlton/2003-04-23: This uses the fact that we currently +- only have using directives in static blocks, because we only +- generate using directives from anonymous namespaces. Eventually, +- when we support using directives everywhere, we'll want to replace +- this by some iterator functions. */ ++ any. Each BLOCK_NAMESPACE()->USING already contains all the namespaces ++ imported at that code point - even those from its parent blocks. */ + + struct using_direct * + block_using (const struct block *block) + { +- const struct block *static_block = block_static_block (block); +- +- if (static_block == NULL +- || BLOCK_NAMESPACE (static_block) == NULL) ++ if (block == NULL || BLOCK_NAMESPACE (block) == NULL) + return NULL; + else +- return BLOCK_NAMESPACE (static_block)->using; ++ return BLOCK_NAMESPACE (block)->using; + } + + /* Set BLOCK's using member to USING; if needed, allocate memory via +diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c +index b23b294..531c43d 100644 +--- a/gdb/breakpoint.c ++++ b/gdb/breakpoint.c +@@ -191,6 +191,8 @@ static int is_hardware_watchpoint (struct breakpoint *bpt); + + static void insert_breakpoint_locations (void); + ++static int syscall_catchpoint_p (struct breakpoint *b); ++ + static const char * + bpdisp_text (enum bpdisp disp) + { +@@ -341,6 +343,18 @@ set_breakpoint_count (int num) + value_from_longest (builtin_type_int32, (LONGEST) num)); + } + ++/* Used in run_command to reset syscall catchpoints fields. */ ++ ++void ++clear_syscall_catchpoints_info (void) ++{ ++ struct breakpoint *b; ++ ++ ALL_BREAKPOINTS (b) ++ if (syscall_catchpoint_p (b)) ++ b->syscall_number = UNKNOWN_SYSCALL; ++} ++ + /* Used in run_command to zero the hit count when a new run starts. */ + + void +@@ -523,6 +537,53 @@ get_number_or_range (char **pp) + + + ++/* Set break condition of breakpoint B to EXP. */ ++ ++void ++set_breakpoint_condition (struct breakpoint *b, char *exp, int from_tty) ++{ ++ struct bp_location *loc = b->loc; ++ ++ for (; loc; loc = loc->next) ++ { ++ if (loc->cond) ++ { ++ xfree (loc->cond); ++ loc->cond = 0; ++ } ++ } ++ ++ if (b->cond_string != NULL) ++ xfree (b->cond_string); ++ ++ if (*exp == 0) ++ { ++ b->cond_string = NULL; ++ if (from_tty) ++ printf_filtered (_("Breakpoint %d now unconditional.\n"), b->number); ++ } ++ else ++ { ++ char *arg = exp; ++ ++ /* I don't know if it matters whether this is the string the user ++ typed in or the decompiled expression. */ ++ b->cond_string = savestring (arg, strlen (arg)); ++ b->condition_not_parsed = 0; ++ for (loc = b->loc; loc; loc = loc->next) ++ { ++ arg = exp; ++ loc->cond = ++ parse_exp_1 (&arg, block_for_pc (loc->address), 0); ++ if (*arg) ++ error (_("Junk at end of expression")); ++ } ++ } ++ ++ breakpoints_changed (); ++ observer_notify_breakpoint_modified (b->number); ++} ++ + /* condition N EXP -- set break condition of breakpoint N to EXP. */ + + static void +@@ -543,42 +604,7 @@ condition_command (char *arg, int from_tty) + ALL_BREAKPOINTS (b) + if (b->number == bnum) + { +- struct bp_location *loc = b->loc; +- for (; loc; loc = loc->next) +- { +- if (loc->cond) +- { +- xfree (loc->cond); +- loc->cond = 0; +- } +- } +- if (b->cond_string != NULL) +- xfree (b->cond_string); +- +- if (*p == 0) +- { +- b->cond_string = NULL; +- if (from_tty) +- printf_filtered (_("Breakpoint %d now unconditional.\n"), bnum); +- } +- else +- { +- arg = p; +- /* I don't know if it matters whether this is the string the user +- typed in or the decompiled expression. */ +- b->cond_string = savestring (arg, strlen (arg)); +- b->condition_not_parsed = 0; +- for (loc = b->loc; loc; loc = loc->next) +- { +- arg = p; +- loc->cond = +- parse_exp_1 (&arg, block_for_pc (loc->address), 0); +- if (*arg) +- error (_("Junk at end of expression")); +- } +- } +- breakpoints_changed (); +- observer_notify_breakpoint_modified (b->number); ++ set_breakpoint_condition (b, p, from_tty); + return; + } + +@@ -961,7 +987,7 @@ update_watchpoint (struct breakpoint *b, int reparse) + int len, type; + struct bp_location *loc, **tmp; + +- addr = VALUE_ADDRESS (v) + value_offset (v); ++ addr = value_address (v); + len = TYPE_LENGTH (value_type (v)); + type = hw_write; + if (b->type == bp_read_watchpoint) +@@ -3948,8 +3974,8 @@ check_duplicates_for (CORE_ADDR address, struct obj_section *section) + } + + /* If we found a permanent breakpoint at this address, go over the +- list again and declare all the other breakpoints there to be the +- duplicates. */ ++ list again and declare all the other breakpoints there (except ++ other permanent breakpoints) to be the duplicates. */ + if (perm_bp) + { + perm_bp->duplicate = 0; +@@ -3963,7 +3989,8 @@ check_duplicates_for (CORE_ADDR address, struct obj_section *section) + ALL_BP_LOCATIONS (b) + if (b != perm_bp) + { +- if (b->owner->enable_state != bp_disabled ++ if (b->owner->enable_state != bp_permanent ++ && b->owner->enable_state != bp_disabled + && b->owner->enable_state != bp_call_disabled + && b->enabled && !b->shlib_disabled + && b->address == address /* address / overlay match */ +@@ -4134,6 +4161,8 @@ set_raw_breakpoint_without_location (enum bptype bptype) + b->frame_id = null_frame_id; + b->forked_inferior_pid = null_ptid; + b->exec_pathname = NULL; ++ b->syscalls_to_be_caught = NULL; ++ b->syscall_number = UNKNOWN_SYSCALL; + b->ops = NULL; + b->condition_not_parsed = 0; + +@@ -4660,7 +4689,241 @@ static struct breakpoint_ops catch_vfork_breakpoint_ops = + print_mention_catch_vfork + }; + +-/* Create a new breakpoint of the bp_catchpoint kind and return it. ++/* We keep a count of the number of times the user has requested a ++ particular syscall to be tracked, and pass this information to the ++ target. This lets capable targets implement filtering directly. */ ++ ++/* Number of times that "any" syscall is requested. */ ++static int any_syscall_count; ++ ++/* Count of each system call. */ ++static int *syscalls_counts; ++ ++/* Number of system entries in SYSCALLS_COUNTS. */ ++static int syscalls_size; ++ ++/* This counts all syscall catch requests, so we can readily determine ++ if any catching is necessary. */ ++static int total_syscalls_count; ++ ++/* Implement the "insert" breakpoint_ops method for syscall ++ catchpoints. */ ++ ++static void ++insert_catch_syscall (struct breakpoint *b) ++{ ++ ++total_syscalls_count; ++ if (!b->syscalls_to_be_caught) ++ ++any_syscall_count; ++ else ++ { ++ struct syscall_filter *iter; ++ for (iter = b->syscalls_to_be_caught; iter; iter = iter->next) ++ { ++ if (iter->syscall >= syscalls_size) ++ { ++ syscalls_counts = xrealloc (syscalls_counts, ++ (iter->syscall + 1) * sizeof (int)); ++ memset (&syscalls_counts[syscalls_size], 0, ++ (iter->syscall + 1 - syscalls_size) * sizeof (int)); ++ } ++ ++syscalls_counts[iter->syscall]; ++ } ++ } ++ ++ target_set_syscall_catchpoint (PIDGET (inferior_ptid), ++ total_syscalls_count != 0, ++ any_syscall_count, ++ syscalls_size, ++ syscalls_counts); ++} ++ ++/* Implement the "remove" breakpoint_ops method for syscall ++ catchpoints. */ ++ ++static int ++remove_catch_syscall (struct breakpoint *b) ++{ ++ --total_syscalls_count; ++ if (!b->syscalls_to_be_caught) ++ --any_syscall_count; ++ else ++ { ++ struct syscall_filter *iter; ++ for (iter = b->syscalls_to_be_caught; iter; iter = iter->next) ++ { ++ if (iter->syscall >= syscalls_size) ++ { ++ /* Shouldn't happen. */ ++ continue; ++ } ++ --syscalls_counts[iter->syscall]; ++ } ++ } ++ ++ return target_set_syscall_catchpoint (PIDGET (inferior_ptid), ++ total_syscalls_count != 0, ++ any_syscall_count, ++ syscalls_size, ++ syscalls_counts); ++} ++ ++/* Implement the "breakpoint_hit" breakpoint_ops method for syscall ++ catchpoints. */ ++ ++static int ++breakpoint_hit_catch_syscall (struct breakpoint *b) ++{ ++ /* We must check if we are catching specific syscalls in this breakpoint. ++ If we are, then we must guarantee that the called syscall is the same ++ syscall we are catching. */ ++ int syscall_number = 0; ++ ++ if (!inferior_has_called_syscall (inferior_ptid, &syscall_number)) ++ return 0; ++ ++ /* Now, checking if the syscall is the same. */ ++ if (b->syscalls_to_be_caught) ++ { ++ struct syscall_filter *iter; ++ for (iter = b->syscalls_to_be_caught; iter; iter = iter->next) ++ if (syscall_number == iter->syscall) ++ break; ++ /* Not the same. */ ++ if (!iter) ++ return 0; ++ } ++ ++ /* It's the same syscall. We can update the breakpoint struct ++ with the correct information. */ ++ b->syscall_number = syscall_number; ++ ++ return 1; ++} ++ ++/* Implement the "print_it" breakpoint_ops method for syscall ++ catchpoints. */ ++ ++static enum print_stop_action ++print_it_catch_syscall (struct breakpoint *b) ++{ ++ /* These are needed because we want to know in which state a ++ syscall is. It can be in the TARGET_WAITKIND_SYSCALL_ENTRY ++ or TARGET_WAITKIND_SYSCALL_RETURN, and depending on it we ++ must print "called syscall" or "returned from syscall". */ ++ ptid_t ptid; ++ struct target_waitstatus last; ++ struct syscall s; ++ struct cleanup *old_chain; ++ char *syscall_id; ++ ++ gdbarch_get_syscall_by_number (current_gdbarch, b->syscall_number, &s); ++ ++ get_last_target_status (&ptid, &last); ++ ++ annotate_catchpoint (b->number); ++ ++ if (s.name == NULL) ++ syscall_id = xstrprintf ("%d", b->syscall_number); ++ else ++ syscall_id = xstrprintf ("'%s'", s.name); ++ ++ old_chain = make_cleanup (xfree, syscall_id); ++ ++ if (last.kind == TARGET_WAITKIND_SYSCALL_ENTRY) ++ printf_filtered (_("\nCatchpoint %d (call to syscall %s), "), ++ b->number, syscall_id); ++ else ++ printf_filtered (_("\nCatchpoint %d (returned from syscall %s), "), ++ b->number, syscall_id); ++ ++ do_cleanups (old_chain); ++ ++ return PRINT_SRC_AND_LOC; ++} ++ ++/* Implement the "print_one" breakpoint_ops method for syscall ++ catchpoints. */ ++ ++static void ++print_one_catch_syscall (struct breakpoint *b, CORE_ADDR *last_addr) ++{ ++ struct value_print_options opts; ++ struct syscall s; ++ ++ gdbarch_get_syscall_by_number (current_gdbarch, b->syscall_number, &s); ++ ++ get_user_print_options (&opts); ++ /* Field 4, the address, is omitted (which makes the columns ++ not line up too nicely with the headers, but the effect ++ is relatively readable). */ ++ if (opts.addressprint) ++ ui_out_field_skip (uiout, "addr"); ++ annotate_field (5); ++ ui_out_text (uiout, "syscall \""); ++ if (b->syscall_number != UNKNOWN_SYSCALL) ++ { ++ if (s.name) ++ ui_out_field_string (uiout, "what", s.name); ++ else ++ ui_out_field_int (uiout, "what", b->syscall_number); ++ } ++ else ++ ui_out_field_string (uiout, "what", ""); ++ ui_out_text (uiout, "\" "); ++} ++ ++/* Implement the "print_mention" breakpoint_ops method for syscall ++ catchpoints. */ ++ ++static void ++print_mention_catch_syscall (struct breakpoint *b) ++{ ++ if (b->syscalls_to_be_caught) ++ { ++ struct syscall_filter *iter; ++ printf_filtered (_("Catchpoint %d (syscall(s)"), b->number); ++ for (iter = b->syscalls_to_be_caught; iter; iter = iter->next) ++ { ++ struct syscall s; ++ gdbarch_get_syscall_by_number (current_gdbarch, iter->syscall, &s); ++ ++ if (s.name) ++ printf_filtered (" '%s'", s.name); ++ else ++ printf_filtered (" %d", iter->syscall); ++ } ++ printf_filtered (")"); ++ } ++ else ++ printf_filtered (_("Catchpoint %d (any syscall)"), ++ b->number); ++} ++ ++/* The breakpoint_ops structure to be used in syscall catchpoints. */ ++ ++static struct breakpoint_ops catch_syscall_breakpoint_ops = ++{ ++ insert_catch_syscall, ++ remove_catch_syscall, ++ breakpoint_hit_catch_syscall, ++ print_it_catch_syscall, ++ print_one_catch_syscall, ++ print_mention_catch_syscall ++}; ++ ++/* Returns non-zero if 'b' is a syscall catchpoint. */ ++ ++static int ++syscall_catchpoint_p (struct breakpoint *b) ++{ ++ return (b->ops == &catch_syscall_breakpoint_ops); ++} ++ ++/* Create a new breakpoint of the bp_catchpoint kind and return it, ++ but does NOT mention it nor update the global location list. ++ This is useful if you need to fill more fields in the ++ struct breakpoint before calling mention. + + If TEMPFLAG is non-zero, then make the breakpoint temporary. + If COND_STRING is not NULL, then store it in the breakpoint. +@@ -4668,16 +4931,13 @@ static struct breakpoint_ops catch_vfork_breakpoint_ops = + to the catchpoint. */ + + static struct breakpoint * +-create_catchpoint (int tempflag, char *cond_string, +- struct breakpoint_ops *ops) ++create_catchpoint_without_mention (int tempflag, char *cond_string, ++ struct breakpoint_ops *ops) + { + struct symtab_and_line sal; + struct breakpoint *b; + + init_sal (&sal); +- sal.pc = 0; +- sal.symtab = NULL; +- sal.line = 0; + + b = set_raw_breakpoint (sal, bp_catchpoint); + set_breakpoint_count (breakpoint_count + 1); +@@ -4691,6 +4951,23 @@ create_catchpoint (int tempflag, char *cond_string, + b->disposition = tempflag ? disp_del : disp_donttouch; + b->ops = ops; + ++ return b; ++} ++ ++/* Create a new breakpoint of the bp_catchpoint kind and return it. ++ ++ If TEMPFLAG is non-zero, then make the breakpoint temporary. ++ If COND_STRING is not NULL, then store it in the breakpoint. ++ OPS, if not NULL, is the breakpoint_ops structure associated ++ to the catchpoint. */ ++ ++static struct breakpoint * ++create_catchpoint (int tempflag, char *cond_string, ++ struct breakpoint_ops *ops) ++{ ++ struct breakpoint *b = ++ create_catchpoint_without_mention (tempflag, cond_string, ops); ++ + mention (b); + update_global_location_list (1); + +@@ -4775,6 +5052,23 @@ static struct breakpoint_ops catch_exec_breakpoint_ops = + print_mention_catch_exec + }; + ++static void ++create_syscall_event_catchpoint (int tempflag, struct syscall_filter *filter, ++ struct breakpoint_ops *ops) ++{ ++ struct breakpoint *b = ++ create_catchpoint_without_mention (tempflag, NULL, ops); ++ ++ b->syscalls_to_be_caught = filter; ++ /* We still don't know the syscall that will be caught :-). */ ++ b->syscall_number = UNKNOWN_SYSCALL; ++ ++ /* Now, we have to mention the breakpoint and update the global ++ location list. */ ++ mention (b); ++ update_global_location_list (1); ++} ++ + static int + hw_breakpoint_used_count (void) + { +@@ -5188,7 +5482,6 @@ expand_line_sal_maybe (struct symtab_and_line sal) + struct symtabs_and_lines expanded; + CORE_ADDR original_pc = sal.pc; + char *original_function = NULL; +- int found; + int i; + + /* If we have explicit pc, don't expand. +@@ -5264,14 +5557,42 @@ expand_line_sal_maybe (struct symtab_and_line sal) + + if (original_pc) + { +- found = 0; ++ /* Find all the other PCs for a line of code with multiple instances ++ (locations). If the instruction is in the middle of an instruction ++ block for source line GDB cannot safely find the same instruction in ++ the other compiled instances of the same source line because the other ++ instances may have been compiled completely differently. ++ ++ The testcase gdb.cp/expand-sals.exp shows that breaking at the return ++ address in a caller of the current frame works for the current ++ instance but the breakpoint cannot catch the point (instruction) where ++ the callee returns in the other compiled instances of this source line. ++ ++ The current implementation will place the breakpoint at the expected ++ returning address of the current instance of the caller. But the ++ other instances will get the breakpoint at the first instruction of ++ the source line - therefore before the call would be made. Another ++ possibility would be to place the breakpoint in the other instances at ++ the start of the next source line. ++ ++ A possible heuristics would compare the instructions length of each of ++ the instances of the current source line and if it matches it would ++ place the breakpoint at the same offset. Unfortunately a mistaken ++ guess would possibly crash the inferior. */ ++ ++ CORE_ADDR best = -1; ++ ++ /* Find the nearest preceding PC and set it to ORIGINAL_PC. */ + for (i = 0; i < expanded.nelts; ++i) +- if (expanded.sals[i].pc == original_pc) +- { +- found = 1; +- break; +- } +- gdb_assert (found); ++ if (expanded.sals[i].pc <= original_pc ++ && (best == -1 || expanded.sals[best].pc < expanded.sals[i].pc)) ++ best = i; ++ ++ if (best == -1) ++ error (_("Cannot find the best address for %s out of the %d locations"), ++ paddr (original_pc), expanded.nelts); ++ ++ expanded.sals[best].pc = original_pc; + } + + return expanded; +@@ -5310,8 +5631,6 @@ create_breakpoints (struct symtabs_and_lines sals, char **addr_string, + cond_string, type, disposition, + thread, ignore_count, ops, from_tty, enabled); + } +- +- update_global_location_list (1); + } + + /* Parse ARG which is assumed to be a SAL specification possibly +@@ -5637,7 +5956,6 @@ break_command_really (char *arg, char *cond_string, int thread, + b->ops = ops; + b->enable_state = enabled ? bp_enabled : bp_disabled; + +- update_global_location_list (1); + mention (b); + } + +@@ -5649,6 +5967,11 @@ break_command_really (char *arg, char *cond_string, int thread, + discard_cleanups (breakpoint_chain); + /* But cleanup everything else. */ + do_cleanups (old_chain); ++ ++ /* Have already BREAKPOINT_CHAIN discarded as we may get an exception while ++ inserting the breakpoints which would double-free the resources both by ++ BREAKPOINT_CHAIN now and during DELETE_BREAKPOINT in the future. */ ++ update_global_location_list (1); + } + + /* Set a breakpoint. +@@ -6131,7 +6454,7 @@ can_use_hardware_watchpoint (struct value *v) + || (TYPE_CODE (vtype) != TYPE_CODE_STRUCT + && TYPE_CODE (vtype) != TYPE_CODE_ARRAY)) + { +- CORE_ADDR vaddr = VALUE_ADDRESS (v) + value_offset (v); ++ CORE_ADDR vaddr = value_address (v); + int len = TYPE_LENGTH (value_type (v)); + + if (!TARGET_REGION_OK_FOR_HW_WATCHPOINT (vaddr, len)) +@@ -6668,6 +6991,122 @@ catch_ada_exception_command (char *arg, int from_tty, + from_tty); + } + ++/* Cleanup function for a syscall filter list. */ ++static void ++clean_up_filters (void *arg) ++{ ++ struct syscall_filter *iter = *(struct syscall_filter **) arg; ++ while (iter) ++ { ++ struct syscall_filter *next = iter->next; ++ xfree (iter); ++ iter = next; ++ } ++} ++ ++/* Splits the argument using space as delimiter. Returns an xmalloc'd ++ filter list, or NULL if no filtering is required. */ ++static struct syscall_filter * ++catch_syscall_split_args (char *arg) ++{ ++ struct syscall_filter *result = NULL; ++ struct cleanup *cleanup = make_cleanup (clean_up_filters, &result); ++ ++ while (*arg != '\0') ++ { ++ int i, syscall_number; ++ char *endptr; ++ char cur_name[128]; ++ struct syscall_filter *new_filter; ++ struct syscall s; ++ ++ /* Skip whitespace. */ ++ while (isspace (*arg)) ++ arg++; ++ ++ for (i = 0; arg[i] && !isspace (arg[i]); ++i) ++ cur_name[i] = arg[i]; ++ cur_name[i] = '\0'; ++ arg += i; ++ ++ /* Check if the user provided a syscall name or a number. */ ++ syscall_number = (int) strtol (cur_name, &endptr, 10); ++ if (*endptr == '\0') ++ { ++ gdbarch_get_syscall_by_number (current_gdbarch, ++ syscall_number, &s); ++ ++ if (s.name == NULL) ++ /* We can issue just a warning, but still create the catchpoint. ++ This is because, even not knowing the syscall name that ++ this number represents, we can still try to catch the syscall ++ number. */ ++ warning (_("The number '%d' does not represent a known syscall."), ++ syscall_number); ++ } ++ else ++ { ++ /* We have a name. Let's check if it's valid and convert it ++ to a number. */ ++ gdbarch_get_syscall_by_name (current_gdbarch, cur_name, &s); ++ ++ if (s.number == UNKNOWN_SYSCALL) ++ /* Here we have to issue an error instead of a warning, because ++ GDB cannot do anything useful if there's no syscall number to ++ be caught. */ ++ error (_("Unknown syscall name '%s'."), cur_name); ++ } ++ ++ /* Ok, it's valid. */ ++ new_filter = XNEW (struct syscall_filter); ++ new_filter->syscall = s.number; ++ new_filter->next = result; ++ result = new_filter; ++ } ++ ++ discard_cleanups (cleanup); ++ return result; ++} ++ ++/* Implement the "catch syscall" command. */ ++ ++static void ++catch_syscall_command_1 (char *arg, int from_tty, struct cmd_list_element *command) ++{ ++ int tempflag; ++ struct syscall_filter *filter; ++ struct syscall s; ++ ++ /* Checking if the feature if supported. */ ++ if (gdbarch_get_syscall_number_p (current_gdbarch) == 0) ++ error (_("The feature 'catch syscall' is not supported on \ ++this architeture yet.")); ++ ++ tempflag = get_cmd_context (command) == CATCH_TEMPORARY; ++ ++ ep_skip_leading_whitespace (&arg); ++ ++ /* We need to do this first "dummy" translation in order ++ to get the syscall XML file loaded or, most important, ++ to display a warning to the user if there's no XML file ++ for his/her architecture. */ ++ gdbarch_get_syscall_by_number (current_gdbarch, 0, &s); ++ ++ /* The allowed syntax is: ++ catch syscall ++ catch syscall [ ... ] ++ ++ Let's check if there's a syscall name. */ ++ ++ if (arg != NULL) ++ filter = catch_syscall_split_args (arg); ++ else ++ filter = NULL; ++ ++ create_syscall_event_catchpoint (tempflag, filter, ++ &catch_syscall_breakpoint_ops); ++} ++ + /* Implement the "catch assert" command. */ + + static void +@@ -7134,6 +7573,7 @@ delete_breakpoint (struct breakpoint *bpt) + xfree (bpt->source_file); + if (bpt->exec_pathname != NULL) + xfree (bpt->exec_pathname); ++ clean_up_filters (&bpt->syscalls_to_be_caught); + + /* Be sure no bpstat's are pointing at it after it's been freed. */ + /* FIXME, how can we find all bpstat's? +@@ -8041,6 +8481,56 @@ single_step_breakpoint_inserted_here_p (CORE_ADDR pc) + return 0; + } + ++/* Returns 0 if 'bp' is NOT a syscall catchpoint, ++ non-zero otherwise. */ ++static int ++is_syscall_catchpoint_enabled (struct breakpoint *bp) ++{ ++ if (syscall_catchpoint_p (bp) ++ && bp->enable_state != bp_disabled ++ && bp->enable_state != bp_call_disabled) ++ return 1; ++ else ++ return 0; ++} ++ ++int ++catch_syscall_enabled (void) ++{ ++ return total_syscalls_count != 0; ++} ++ ++int ++catching_syscall_number (int syscall_number) ++{ ++ struct breakpoint *bp; ++ ++ ALL_BREAKPOINTS (bp) ++ if (is_syscall_catchpoint_enabled (bp)) ++ { ++ if (bp->syscalls_to_be_caught) ++ { ++ struct syscall_filter *iter; ++ for (iter = bp->syscalls_to_be_caught; iter; iter = iter->next) ++ if (syscall_number == iter->syscall) ++ return 1; ++ } ++ else ++ return 1; ++ } ++ ++ return 0; ++} ++ ++/* Complete syscall names. Used by "catch syscall". */ ++static char ** ++catch_syscall_completer (struct cmd_list_element *self, char *text, char *word) ++{ ++ const char **list = ++ gdbarch_get_syscall_names (current_gdbarch); ++ return (list == NULL) ? NULL : complete_on_enum (list, text, word); ++} ++ + + /* This help string is used for the break, hbreak, tbreak and thbreak commands. + It is defined as a macro to prevent duplication. +@@ -8073,6 +8563,8 @@ static void + add_catch_command (char *name, char *docstring, + void (*sfunc) (char *args, int from_tty, + struct cmd_list_element *command), ++ char **(*completion_function) (struct cmd_list_element *self, ++ char *text, char *word), + void *user_data_catch, + void *user_data_tcatch) + { +@@ -8082,11 +8574,13 @@ add_catch_command (char *name, char *docstring, + &catch_cmdlist); + set_cmd_sfunc (command, sfunc); + set_cmd_context (command, user_data_catch); ++ set_cmd_completer (command, completion_function); + + command = add_cmd (name, class_breakpoint, NULL, docstring, + &tcatch_cmdlist); + set_cmd_sfunc (command, sfunc); + set_cmd_context (command, user_data_tcatch); ++ set_cmd_completer (command, completion_function); + } + + void +@@ -8361,36 +8855,50 @@ Set temporary catchpoints to catch events."), + Catch an exception, when caught.\n\ + With an argument, catch only exceptions with the given name."), + catch_catch_command, ++ NULL, + CATCH_PERMANENT, + CATCH_TEMPORARY); + add_catch_command ("throw", _("\ + Catch an exception, when thrown.\n\ + With an argument, catch only exceptions with the given name."), + catch_throw_command, ++ NULL, + CATCH_PERMANENT, + CATCH_TEMPORARY); + add_catch_command ("fork", _("Catch calls to fork."), + catch_fork_command_1, ++ NULL, + (void *) (uintptr_t) catch_fork_permanent, + (void *) (uintptr_t) catch_fork_temporary); + add_catch_command ("vfork", _("Catch calls to vfork."), + catch_fork_command_1, ++ NULL, + (void *) (uintptr_t) catch_vfork_permanent, + (void *) (uintptr_t) catch_vfork_temporary); + add_catch_command ("exec", _("Catch calls to exec."), + catch_exec_command_1, ++ NULL, + CATCH_PERMANENT, + CATCH_TEMPORARY); ++ add_catch_command ("syscall", _("\ ++Catch system calls.\n\ ++With an argument, catch only that syscall."), ++ catch_syscall_command_1, ++ catch_syscall_completer, ++ CATCH_PERMANENT, ++ CATCH_TEMPORARY); + add_catch_command ("exception", _("\ + Catch Ada exceptions, when raised.\n\ + With an argument, catch only exceptions with the given name."), + catch_ada_exception_command, ++ NULL, + CATCH_PERMANENT, + CATCH_TEMPORARY); + add_catch_command ("assert", _("\ + Catch failed Ada assertions, when raised.\n\ + With an argument, catch only exceptions with the given name."), + catch_assert_command, ++ NULL, + CATCH_PERMANENT, + CATCH_TEMPORARY); + +diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h +index 94287de..8552e1b 100644 +--- a/gdb/breakpoint.h ++++ b/gdb/breakpoint.h +@@ -33,7 +33,8 @@ struct block; + + #define BREAKPOINT_MAX 16 + +-/* Type of breakpoint. */ ++ ++/* Type of breakpoint. */ + /* FIXME In the future, we should fold all other breakpoint-like things into + here. This includes: + +@@ -337,6 +338,17 @@ enum watchpoint_triggered + watch_triggered_yes + }; + ++/* A syscall filter is represented as a linked list of syscall ++ numbers. */ ++struct syscall_filter ++{ ++ /* The system call to accept. */ ++ int syscall; ++ ++ /* The next filter. */ ++ struct syscall_filter *next; ++}; ++ + typedef struct bp_location *bp_location_p; + DEF_VEC_P(bp_location_p); + +@@ -442,6 +454,20 @@ struct breakpoint + triggered. */ + char *exec_pathname; + ++ /* Syscall number used for the 'catch syscall' feature. ++ If no syscall has been called, its value is UNKNOWN_SYSCALL. ++ Otherwise, it holds the system call number in the target. ++ ++ This field is only valid immediately after this catchpoint has ++ triggered. */ ++ int syscall_number; ++ ++ /* Syscall numbers used for the 'catch syscall' feature. ++ If no syscall has been specified for filtering, its value is NULL. ++ Otherwise, it holds a list of all syscalls to be caught. ++ The list elements are allocated with xmalloc. */ ++ struct syscall_filter *syscalls_to_be_caught; ++ + /* Methods associated with this breakpoint. */ + struct breakpoint_ops *ops; + +@@ -783,6 +809,8 @@ extern void enable_watchpoints_after_interactive_call_stop (void); + extern enum command_control_type commands_from_control_command + (char *arg, struct command_line *cmd); + ++extern void clear_syscall_catchpoints_info (void); ++ + extern void clear_breakpoint_hit_counts (void); + + extern int get_number (char **); +@@ -857,7 +885,19 @@ extern int breakpoints_always_inserted_mode (void); + in our opinion won't ever trigger. */ + extern void breakpoint_retire_moribund (void); + ++/* Checks if we are catching syscalls or not. ++ Returns 0 if not, greater than 0 if we are. */ ++extern int catch_syscall_enabled (void); ++ ++/* Checks if we are catching syscalls with the specific ++ syscall_number. Used for "filtering" the catchpoints. ++ Returns 0 if not, greater than 0 if we are. */ ++extern int catching_syscall_number (int syscall_number); ++ + /* Tell a breakpoint to be quiet. */ + extern void make_breakpoint_silent (struct breakpoint *); + ++/* Set break condition of breakpoint B to EXP. */ ++extern void set_breakpoint_condition (struct breakpoint *b, char *exp, int from_tty); ++ + #endif /* !defined (BREAKPOINT_H) */ +diff --git a/gdb/buildsym.c b/gdb/buildsym.c +index 55ace15..2722daa 100644 +--- a/gdb/buildsym.c ++++ b/gdb/buildsym.c +@@ -384,6 +384,8 @@ finish_block (struct symbol *symbol, struct pending **listhead, + opblock = pblock; + } + ++ block_set_using (block, using_directives, &objfile->objfile_obstack); ++ + record_pending_block (objfile, block, opblock); + + return block; +@@ -815,10 +817,6 @@ start_symtab (char *name, char *dirname, CORE_ADDR start_addr) + /* We shouldn't have any address map at this point. */ + gdb_assert (! pending_addrmap); + +- /* Set up support for C++ namespace support, in case we need it. */ +- +- cp_initialize_namespace (); +- + /* Initialize the list of sub source files with one entry for this + file (the top-level source file). */ + +@@ -1015,8 +1013,6 @@ end_symtab (CORE_ADDR end_addr, struct objfile *objfile, int section) + finish_block (0, &global_symbols, 0, last_source_start_addr, end_addr, + objfile); + blockvector = make_blockvector (objfile); +- cp_finalize_namespace (BLOCKVECTOR_BLOCK (blockvector, STATIC_BLOCK), +- &objfile->objfile_obstack); + } + + /* Read the line table if it has to be read separately. */ +@@ -1202,10 +1198,12 @@ push_context (int desc, CORE_ADDR valu) + new->params = param_symbols; + new->old_blocks = pending_blocks; + new->start_addr = valu; ++ new->using_directives = using_directives; + new->name = NULL; + + local_symbols = NULL; + param_symbols = NULL; ++ using_directives = NULL; + + return new; + } +diff --git a/gdb/buildsym.h b/gdb/buildsym.h +index bf23ecc..f542aca 100644 +--- a/gdb/buildsym.h ++++ b/gdb/buildsym.h +@@ -125,6 +125,10 @@ EXTERN struct pending *local_symbols; + + EXTERN struct pending *param_symbols; + ++/* using directives local to lexical context */ ++ ++EXTERN struct using_direct *using_directives; ++ + /* Stack representing unclosed lexical contexts (that will become + blocks, eventually). */ + +@@ -138,6 +142,10 @@ struct context_stack + + struct pending *params; + ++ /* Pending using directives at the time we entered */ ++ ++ struct using_direct *using_directives; ++ + /* Pointer into blocklist as of entry */ + + struct pending_block *old_blocks; +diff --git a/gdb/c-exp.y b/gdb/c-exp.y +index d4bbbcc..107452a 100644 +--- a/gdb/c-exp.y ++++ b/gdb/c-exp.y +@@ -119,6 +119,8 @@ static int yylex (void); + + void yyerror (char *); + ++/* Cleanup for 'nonempty_typelist' */ ++static struct cleanup *typelist_cleanup; + %} + + /* Although the yacc "value" of an expression is not used, +@@ -143,6 +145,7 @@ void yyerror (char *); + struct symbol *sym; + struct type *tval; + struct stoken sval; ++ struct typed_stoken tsval; + struct ttype tsym; + struct symtoken ssym; + int voidval; +@@ -150,6 +153,7 @@ void yyerror (char *); + enum exp_opcode opcode; + struct internalvar *ivar; + ++ struct stoken_vector svec; + struct type **tvec; + int *ivec; + } +@@ -182,11 +186,13 @@ static int parse_number (char *, int, int, YYSTYPE *); + Contexts where this distinction is not important can use the + nonterminal "name", which matches either NAME or TYPENAME. */ + +-%token STRING ++%token STRING ++%token CHAR + %token NAME /* BLOCKNAME defined below to give it higher precedence. */ + %token COMPLETE + %token TYPENAME +-%type name string_exp ++%type name ++%type string_exp + %type name_not_typename + %type typename + +@@ -399,6 +405,38 @@ arglist : arglist ',' exp %prec ABOVE_COMMA + { arglist_len++; } + ; + ++exp : exp '(' nonempty_typelist ')' ++ { int i; ++ /* What to do about freeing memory if ++ there is an error during parsing? */ ++ write_exp_elt_opcode (TYPE_INSTANCE); ++ write_exp_elt_longcst ((LONGEST) $3[0]); ++ for (i = 0; i < $3[0]; ++i) ++ write_exp_elt_type ($3[i + 1]); ++ write_exp_elt_longcst((LONGEST) $3[0]); ++ write_exp_elt_opcode (TYPE_INSTANCE); ++ do_cleanups (typelist_cleanup); ++ } ++ ; ++ ++/* ++exp : BLOCKNAME '(' nonempty_typelist ')' ++ { int i; ++ write_exp_elt_opcode (TYPE_INSTANCE_LOOKUP); ++ write_exp_elt_sym ($1.sym); ++ write_exp_elt_opcode (TYPE_INSTANCE_LOOKUP); ++ ++ write_exp_elt_opcode (TYPE_INSTANCE); ++ write_exp_elt_longcst ((LONGEST) $3[0]); ++ for (i = 0; i < $3[0]; ++i) ++ write_exp_elt_type ($3[i + 1]); ++ write_exp_elt_longcst((LONGEST) $3[0]); ++ write_exp_elt_opcode (TYPE_INSTANCE); ++ do_cleanups (typelist_cleanup); ++ } ++ ; ++*/ ++ + rcurly : '}' + { $$ = end_arglist () - 1; } + ; +@@ -524,6 +562,15 @@ exp : INT + write_exp_elt_opcode (OP_LONG); } + ; + ++exp : CHAR ++ { ++ struct stoken_vector vec; ++ vec.len = 1; ++ vec.tokens = &$1; ++ write_exp_string_vector ($1.type, &vec); ++ } ++ ; ++ + exp : NAME_OR_INT + { YYSTYPE val; + parse_number ($1.stoken.ptr, $1.stoken.length, 0, &val); +@@ -572,48 +619,64 @@ string_exp: + string. Note that we follow the + NUL-termination convention of the + lexer. */ +- $$.length = $1.length; +- $$.ptr = malloc ($1.length + 1); +- memcpy ($$.ptr, $1.ptr, $1.length + 1); ++ struct typed_stoken *vec = XNEW (struct typed_stoken); ++ $$.len = 1; ++ $$.tokens = vec; ++ ++ vec->type = $1.type; ++ vec->length = $1.length; ++ vec->ptr = malloc ($1.length + 1); ++ memcpy (vec->ptr, $1.ptr, $1.length + 1); + } + + | string_exp STRING + { + /* Note that we NUL-terminate here, but just + for convenience. */ +- struct stoken t; +- t.length = $1.length + $2.length; +- t.ptr = malloc (t.length + 1); +- memcpy (t.ptr, $1.ptr, $1.length); +- memcpy (t.ptr + $1.length, $2.ptr, $2.length + 1); +- free ($1.ptr); +- $$ = t; ++ char *p; ++ ++$$.len; ++ $$.tokens = realloc ($$.tokens, ++ $$.len * sizeof (struct typed_stoken)); ++ ++ p = malloc ($2.length + 1); ++ memcpy (p, $2.ptr, $2.length + 1); ++ ++ $$.tokens[$$.len - 1].type = $2.type; ++ $$.tokens[$$.len - 1].length = $2.length; ++ $$.tokens[$$.len - 1].ptr = p; + } + ; + + exp : string_exp +- { /* C strings are converted into array constants with +- an explicit null byte added at the end. Thus +- the array upper bound is the string length. +- There is no such thing in C as a completely empty +- string. */ +- char *sp = $1.ptr; int count = $1.length; +- while (count-- > 0) ++ { ++ int i; ++ enum c_string_type type = C_STRING; ++ ++ for (i = 0; i < $1.len; ++i) + { +- write_exp_elt_opcode (OP_LONG); +- write_exp_elt_type (parse_type->builtin_char); +- write_exp_elt_longcst ((LONGEST)(*sp++)); +- write_exp_elt_opcode (OP_LONG); ++ switch ($1.tokens[i].type) ++ { ++ case C_STRING: ++ break; ++ case C_WIDE_STRING: ++ case C_STRING_16: ++ case C_STRING_32: ++ if (type != C_STRING ++ && type != $1.tokens[i].type) ++ error ("Undefined string concatenation."); ++ type = $1.tokens[i].type; ++ break; ++ default: ++ /* internal error */ ++ internal_error (__FILE__, __LINE__, ++ "unrecognized type in string concatenation"); ++ } + } +- write_exp_elt_opcode (OP_LONG); +- write_exp_elt_type (parse_type->builtin_char); +- write_exp_elt_longcst ((LONGEST)'\0'); +- write_exp_elt_opcode (OP_LONG); +- write_exp_elt_opcode (OP_ARRAY); +- write_exp_elt_longcst ((LONGEST) 0); +- write_exp_elt_longcst ((LONGEST) ($1.length)); +- write_exp_elt_opcode (OP_ARRAY); +- free ($1.ptr); ++ ++ write_exp_string_vector (type, &$1); ++ for (i = 0; i < $1.len; ++i) ++ free ($1.tokens[i].ptr); ++ free ($1.tokens); + } + ; + +@@ -713,12 +776,13 @@ qualified_name: typebase COLONCOLON name + ; + + variable: qualified_name ++ | COLONCOLON qualified_name + | COLONCOLON name + { + char *name = copy_name ($2); + struct symbol *sym; + struct minimal_symbol *msymbol; +- ++ + sym = + lookup_symbol (name, (const struct block *) NULL, + VAR_DOMAIN, (int *) NULL); +@@ -856,7 +920,7 @@ array_mod: '[' ']' + func_mod: '(' ')' + { $$ = 0; } + | '(' nonempty_typelist ')' +- { free ($2); $$ = 0; } ++ { do_cleanups (typelist_cleanup); $$ = 0; } + ; + + /* We used to try to recognize pointer to member types here, but +@@ -1057,12 +1121,15 @@ typename: TYPENAME + nonempty_typelist + : type + { $$ = (struct type **) malloc (sizeof (struct type *) * 2); ++ typelist_cleanup = make_cleanup (free, $$); + $$[0] = 1; /* Number of types in vector */ + $$[1] = $1; + } + | nonempty_typelist ',' type + { int len = sizeof (struct type *) * (++($1[0]) + 1); + $$ = (struct type **) realloc ((char *) $1, len); ++ discard_cleanups (typelist_cleanup); ++ typelist_cleanup = make_cleanup (free, $$); + $$[$$[0]] = $3; + } + ; +@@ -1361,6 +1428,263 @@ parse_number (p, len, parsed_float, putithere) + return INT; + } + ++/* Temporary obstack used for holding strings. */ ++static struct obstack tempbuf; ++static int tempbuf_init; ++ ++/* Parse a C escape sequence. The initial backslash of the sequence ++ is at (*PTR)[-1]. *PTR will be updated to point to just after the ++ last character of the sequence. If OUTPUT is not NULL, the ++ translated form of the escape sequence will be written there. If ++ OUTPUT is NULL, no output is written and the call will only affect ++ *PTR. If an escape sequence is expressed in target bytes, then the ++ entire sequence will simply be copied to OUTPUT. Return 1 if any ++ character was emitted, 0 otherwise. */ ++ ++int ++c_parse_escape (char **ptr, struct obstack *output) ++{ ++ char *tokptr = *ptr; ++ int result = 1; ++ ++ /* Some escape sequences undergo character set conversion. Those we ++ translate here. */ ++ switch (*tokptr) ++ { ++ /* Hex escapes do not undergo character set conversion, so keep ++ the escape sequence for later. */ ++ case 'x': ++ if (output) ++ obstack_grow_str (output, "\\x"); ++ ++tokptr; ++ if (!isxdigit (*tokptr)) ++ error (_("\\x escape without a following hex digit")); ++ while (isxdigit (*tokptr)) ++ { ++ if (output) ++ obstack_1grow (output, *tokptr); ++ ++tokptr; ++ } ++ break; ++ ++ /* Octal escapes do not undergo character set conversion, so ++ keep the escape sequence for later. */ ++ case '0': ++ case '1': ++ case '2': ++ case '3': ++ case '4': ++ case '5': ++ case '6': ++ case '7': ++ if (output) ++ obstack_grow_str (output, "\\"); ++ while (isdigit (*tokptr) && *tokptr != '8' && *tokptr != '9') ++ { ++ if (output) ++ obstack_1grow (output, *tokptr); ++ ++tokptr; ++ } ++ break; ++ ++ /* We handle UCNs later. We could handle them here, but that ++ would mean a spurious error in the case where the UCN could ++ be converted to the target charset but not the host ++ charset. */ ++ case 'u': ++ case 'U': ++ { ++ char c = *tokptr; ++ int i, len = c == 'U' ? 8 : 4; ++ if (output) ++ { ++ obstack_1grow (output, '\\'); ++ obstack_1grow (output, *tokptr); ++ } ++ ++tokptr; ++ if (!isxdigit (*tokptr)) ++ error (_("\\%c escape without a following hex digit"), c); ++ for (i = 0; i < len && isxdigit (*tokptr); ++i) ++ { ++ if (output) ++ obstack_1grow (output, *tokptr); ++ ++tokptr; ++ } ++ } ++ break; ++ ++ /* We must pass backslash through so that it does not ++ cause quoting during the second expansion. */ ++ case '\\': ++ if (output) ++ obstack_grow_str (output, "\\\\"); ++ ++tokptr; ++ break; ++ ++ /* Escapes which undergo conversion. */ ++ case 'a': ++ if (output) ++ obstack_1grow (output, '\a'); ++ ++tokptr; ++ break; ++ case 'b': ++ if (output) ++ obstack_1grow (output, '\b'); ++ ++tokptr; ++ break; ++ case 'f': ++ if (output) ++ obstack_1grow (output, '\f'); ++ ++tokptr; ++ break; ++ case 'n': ++ if (output) ++ obstack_1grow (output, '\n'); ++ ++tokptr; ++ break; ++ case 'r': ++ if (output) ++ obstack_1grow (output, '\r'); ++ ++tokptr; ++ break; ++ case 't': ++ if (output) ++ obstack_1grow (output, '\t'); ++ ++tokptr; ++ break; ++ case 'v': ++ if (output) ++ obstack_1grow (output, '\v'); ++ ++tokptr; ++ break; ++ ++ /* GCC extension. */ ++ case 'e': ++ if (output) ++ obstack_1grow (output, HOST_ESCAPE_CHAR); ++ ++tokptr; ++ break; ++ ++ /* Backslash-newline expands to nothing at all. */ ++ case '\n': ++ ++tokptr; ++ result = 0; ++ break; ++ ++ /* A few escapes just expand to the character itself. */ ++ case '\'': ++ case '\"': ++ case '?': ++ /* GCC extensions. */ ++ case '(': ++ case '{': ++ case '[': ++ case '%': ++ /* Unrecognized escapes turn into the character itself. */ ++ default: ++ if (output) ++ obstack_1grow (output, *tokptr); ++ ++tokptr; ++ break; ++ } ++ *ptr = tokptr; ++ return result; ++} ++ ++/* Parse a string or character literal from TOKPTR. The string or ++ character may be wide or unicode. *OUTPTR is set to just after the ++ end of the literal in the input string. The resulting token is ++ stored in VALUE. This returns a token value, either STRING or ++ CHAR, depending on what was parsed. *HOST_CHARS is set to the ++ number of host characters in the literal. */ ++static int ++parse_string_or_char (char *tokptr, char **outptr, struct typed_stoken *value, ++ int *host_chars) ++{ ++ int quote, i; ++ enum c_string_type type; ++ ++ /* Build the gdb internal form of the input string in tempbuf. Note ++ that the buffer is null byte terminated *only* for the ++ convenience of debugging gdb itself and printing the buffer ++ contents when the buffer contains no embedded nulls. Gdb does ++ not depend upon the buffer being null byte terminated, it uses ++ the length string instead. This allows gdb to handle C strings ++ (as well as strings in other languages) with embedded null ++ bytes */ ++ ++ if (!tempbuf_init) ++ tempbuf_init = 1; ++ else ++ obstack_free (&tempbuf, NULL); ++ obstack_init (&tempbuf); ++ ++ /* Record the string type. */ ++ if (*tokptr == 'L') ++ { ++ type = C_WIDE_STRING; ++ ++tokptr; ++ } ++ else if (*tokptr == 'u') ++ { ++ type = C_STRING_16; ++ ++tokptr; ++ } ++ else if (*tokptr == 'U') ++ { ++ type = C_STRING_32; ++ ++tokptr; ++ } ++ else ++ type = C_STRING; ++ ++ /* Skip the quote. */ ++ quote = *tokptr; ++ if (quote == '\'') ++ type |= C_CHAR; ++ ++tokptr; ++ ++ *host_chars = 0; ++ ++ while (*tokptr) ++ { ++ char c = *tokptr; ++ if (c == '\\') ++ { ++ ++tokptr; ++ *host_chars += c_parse_escape (&tokptr, &tempbuf); ++ } ++ else if (c == quote) ++ break; ++ else ++ { ++ obstack_1grow (&tempbuf, c); ++ ++tokptr; ++ /* FIXME: this does the wrong thing with multi-byte host ++ characters. We could use mbrlen here, but that would ++ make "set host-charset" a bit less useful. */ ++ ++*host_chars; ++ } ++ } ++ ++ if (*tokptr != quote) ++ { ++ if (quote == '"') ++ error ("Unterminated string in expression."); ++ else ++ error ("Unmatched single quote."); ++ } ++ ++tokptr; ++ ++ value->type = type; ++ value->ptr = obstack_base (&tempbuf); ++ value->length = obstack_object_size (&tempbuf); ++ ++ *outptr = tokptr; ++ ++ return quote == '"' ? STRING : CHAR; ++} ++ + struct token + { + char *operator; +@@ -1526,23 +1850,33 @@ static int last_was_structop; + static int + yylex () + { ++ /* name_prefix stores the full qualification of a variable that is ++ specified in the expression. It is used to eleminate confusion ++ during lookup.*/ ++ static char* name_prefix = NULL; ++ static int name_prefix_len = 0; ++ static int terminate_prefix = 0; ++ + int c; + int namelen; + unsigned int i; + char *tokstart; +- char *tokptr; +- int tempbufindex; +- static char *tempbuf; +- static int tempbufsize; +- char * token_string = NULL; +- int class_prefix = 0; + int saw_structop = last_was_structop; + char *copy; + + last_was_structop = 0; +- ++ + retry: +- ++ ++ if(terminate_prefix || ++ lexptr != name_prefix + name_prefix_len // Some token was skiped so clear name_prefix ++ ){ ++ name_prefix = NULL; ++ name_prefix_len = 0; ++ } ++ ++ terminate_prefix = 1; ++ + /* Check if this is a macro invocation that we need to expand. */ + if (! scanning_macro_expansion ()) + { +@@ -1570,10 +1904,19 @@ yylex () + for (i = 0; i < sizeof tokentab2 / sizeof tokentab2[0]; i++) + if (strncmp (tokstart, tokentab2[i].operator, 2) == 0) + { ++ ++ if(tokentab2[i].token == COLONCOLON){ ++ name_prefix_len += 2; ++ terminate_prefix = 0; ++ if(name_prefix == NULL){ ++ name_prefix = lexptr; ++ } ++ } + lexptr += 2; + yylval.opcode = tokentab2[i].opcode; + if (in_parse_field && tokentab2[i].token == ARROW) + last_was_structop = 1; ++ + return tokentab2[i].token; + } + +@@ -1602,51 +1945,13 @@ yylex () + return 0; + + case ' ': ++ name_prefix_len++; ++ terminate_prefix = 0; + case '\t': + case '\n': + lexptr++; + goto retry; + +- case '\'': +- /* We either have a character constant ('0' or '\177' for example) +- or we have a quoted symbol reference ('foo(int,int)' in C++ +- for example). */ +- lexptr++; +- c = *lexptr++; +- if (c == '\\') +- c = parse_escape (&lexptr); +- else if (c == '\'') +- error ("Empty character constant."); +- else if (! host_char_to_target (c, &c)) +- { +- int toklen = lexptr - tokstart + 1; +- char *tok = alloca (toklen + 1); +- memcpy (tok, tokstart, toklen); +- tok[toklen] = '\0'; +- error ("There is no character corresponding to %s in the target " +- "character set `%s'.", tok, target_charset ()); +- } +- +- yylval.typed_val_int.val = c; +- yylval.typed_val_int.type = parse_type->builtin_char; +- +- c = *lexptr++; +- if (c != '\'') +- { +- namelen = skip_quoted (tokstart) - tokstart; +- if (namelen > 2) +- { +- lexptr = tokstart + namelen; +- if (lexptr[-1] != '\'') +- error ("Unmatched single quote."); +- namelen -= 2; +- tokstart++; +- goto tryname; +- } +- error ("Invalid character constant."); +- } +- return INT; +- + case '(': + paren_depth++; + lexptr++; +@@ -1764,70 +2069,33 @@ yylex () + lexptr++; + return c; + ++ case 'L': ++ case 'u': ++ case 'U': ++ if (tokstart[1] != '"' && tokstart[1] != '\'') ++ break; ++ /* Fall through. */ ++ case '\'': + case '"': +- +- /* Build the gdb internal form of the input string in tempbuf, +- translating any standard C escape forms seen. Note that the +- buffer is null byte terminated *only* for the convenience of +- debugging gdb itself and printing the buffer contents when +- the buffer contains no embedded nulls. Gdb does not depend +- upon the buffer being null byte terminated, it uses the length +- string instead. This allows gdb to handle C strings (as well +- as strings in other languages) with embedded null bytes */ +- +- tokptr = ++tokstart; +- tempbufindex = 0; +- +- do { +- char *char_start_pos = tokptr; +- +- /* Grow the static temp buffer if necessary, including allocating +- the first one on demand. */ +- if (tempbufindex + 1 >= tempbufsize) +- { +- tempbuf = (char *) realloc (tempbuf, tempbufsize += 64); +- } +- switch (*tokptr) ++ { ++ int host_len; ++ int result = parse_string_or_char (tokstart, &lexptr, &yylval.tsval, ++ &host_len); ++ if (result == CHAR) + { +- case '\0': +- case '"': +- /* Do nothing, loop will terminate. */ +- break; +- case '\\': +- tokptr++; +- c = parse_escape (&tokptr); +- if (c == -1) ++ if (host_len == 0) ++ error ("Empty character constant."); ++ else if (host_len > 2 && c == '\'') + { +- continue; ++ ++tokstart; ++ namelen = lexptr - tokstart - 1; ++ goto tryname; + } +- tempbuf[tempbufindex++] = c; +- break; +- default: +- c = *tokptr++; +- if (! host_char_to_target (c, &c)) +- { +- int len = tokptr - char_start_pos; +- char *copy = alloca (len + 1); +- memcpy (copy, char_start_pos, len); +- copy[len] = '\0'; +- +- error ("There is no character corresponding to `%s' " +- "in the target character set `%s'.", +- copy, target_charset ()); +- } +- tempbuf[tempbufindex++] = c; +- break; ++ else if (host_len > 1) ++ error ("Invalid character constant."); + } +- } while ((*tokptr != '"') && (*tokptr != '\0')); +- if (*tokptr++ != '"') +- { +- error ("Unterminated string in expression."); +- } +- tempbuf[tempbufindex] = '\0'; /* See note above */ +- yylval.sval.ptr = tempbuf; +- yylval.sval.length = tempbufindex; +- lexptr = tokptr; +- return (STRING); ++ return result; ++ } + } + + if (!(c == '_' || c == '$' +@@ -1836,11 +2104,13 @@ yylex () + error ("Invalid character '%c' in expression.", c); + + /* It's a name. See how long it is. */ ++ + namelen = 0; + for (c = tokstart[namelen]; + (c == '_' || c == '$' || (c >= '0' && c <= '9') + || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '<');) + { ++ + /* Template parameter lists are part of the name. + FIXME: This mishandles `print $a<4&&$a>3'. */ + +@@ -1904,14 +2174,29 @@ yylex () + currently as names of types; NAME for other symbols. + The caller is not constrained to care about the distinction. */ + { ++ char *tmp = copy; + struct symbol *sym; + int is_a_field_of_this = 0; + int hextype; + +- sym = lookup_symbol (copy, expression_context_block, ++ if(name_prefix != NULL){ ++ tmp = savestring (name_prefix, name_prefix_len+namelen); ++ } ++ ++ sym = lookup_symbol (tmp, expression_context_block, + VAR_DOMAIN, + parse_language->la_language == language_cplus + ? &is_a_field_of_this : (int *) NULL); ++ ++ /* keep this name as prefix for the next name */ ++ if(sym){ ++ if(name_prefix == NULL){ ++ name_prefix = tokstart; ++ } ++ name_prefix_len += namelen; ++ terminate_prefix = 0; ++ } ++ + /* Call lookup_symtab, not lookup_partial_symtab, in case there are + no psymtabs (coff, xcoff, or some future change to blow away the + psymtabs once once symbols are read). */ +@@ -1970,6 +2255,7 @@ yylex () + yylval.ssym.is_a_field_of_this = is_a_field_of_this; + if (in_parse_field && *lexptr == '\0') + saw_name_at_eof = 1; ++ + return NAME; + } + } +diff --git a/gdb/c-lang.c b/gdb/c-lang.c +index 8b5410f..188755b 100644 +--- a/gdb/c-lang.c ++++ b/gdb/c-lang.c +@@ -33,48 +33,304 @@ + #include "demangle.h" + #include "cp-abi.h" + #include "cp-support.h" ++#include "gdb_obstack.h" ++#include ++#include ++#include + + extern void _initialize_c_language (void); +-static void c_emit_char (int c, struct ui_file * stream, int quoter); ++ ++/* Given a C string type, STR_TYPE, return the corresponding target ++ character set name. */ ++ ++static const char * ++charset_for_string_type (enum c_string_type str_type) ++{ ++ switch (str_type & ~C_CHAR) ++ { ++ case C_STRING: ++ return target_charset (); ++ case C_WIDE_STRING: ++ return target_wide_charset (); ++ case C_STRING_16: ++ /* FIXME: UCS-2 is not always correct. */ ++ if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG) ++ return "UCS-2BE"; ++ else ++ return "UCS-2LE"; ++ case C_STRING_32: ++ /* FIXME: UCS-4 is not always correct. */ ++ if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG) ++ return "UCS-4BE"; ++ else ++ return "UCS-4LE"; ++ } ++ internal_error (__FILE__, __LINE__, "unhandled c_string_type"); ++} ++ ++/* Classify ELTTYPE according to what kind of character it is. Return ++ the enum constant representing the character type. Also set ++ *ENCODING to the name of the character set to use when converting ++ characters of this type to the host character set. */ ++ ++static enum c_string_type ++classify_type (struct type *elttype, const char **encoding) ++{ ++ struct type *saved_type; ++ enum c_string_type result; ++ ++ /* We do one or two passes -- one on ELTTYPE, and then maybe a ++ second one on a typedef target. */ ++ do ++ { ++ char *name = TYPE_NAME (elttype); ++ ++ if (TYPE_CODE (elttype) == TYPE_CODE_CHAR || !name) ++ { ++ result = C_CHAR; ++ goto done; ++ } ++ ++ if (!strcmp (name, "wchar_t")) ++ { ++ result = C_WIDE_CHAR; ++ goto done; ++ } ++ ++ if (!strcmp (name, "char16_t")) ++ { ++ result = C_CHAR_16; ++ goto done; ++ } ++ ++ if (!strcmp (name, "char32_t")) ++ { ++ result = C_CHAR_32; ++ goto done; ++ } ++ ++ saved_type = elttype; ++ CHECK_TYPEDEF (elttype); ++ } ++ while (elttype != saved_type); ++ ++ /* Punt. */ ++ result = C_CHAR; ++ ++ done: ++ *encoding = charset_for_string_type (result); ++ return result; ++} ++ ++/* Return true if print_wchar can display W without resorting to a ++ numeric escape, false otherwise. */ ++ ++static int ++wchar_printable (wchar_t w) ++{ ++ return (iswprint (w) ++ || w == L'\a' || w == L'\b' || w == L'\f' || w == L'\n' ++ || w == L'\r' || w == L'\t' || w == L'\v'); ++} ++ ++/* A helper function that converts the contents of STRING to wide ++ characters and then appends them to OUTPUT. */ ++ ++static void ++append_string_as_wide (const char *string, struct obstack *output) ++{ ++ for (; *string; ++string) ++ { ++ wchar_t w = btowc (*string); ++ obstack_grow (output, &w, sizeof (wchar_t)); ++ } ++} ++ ++/* Print a wide character W to OUTPUT. ORIG is a pointer to the ++ original (target) bytes representing the character, ORIG_LEN is the ++ number of valid bytes. WIDTH is the number of bytes in a base ++ characters of the type. OUTPUT is an obstack to which wide ++ characters are emitted. QUOTER is a (narrow) character indicating ++ the style of quotes surrounding the character to be printed. ++ NEED_ESCAPE is an in/out flag which is used to track numeric ++ escapes across calls. */ ++ ++static void ++print_wchar (wint_t w, const gdb_byte *orig, int orig_len, ++ int width, struct obstack *output, int quoter, ++ int *need_escapep) ++{ ++ int need_escape = *need_escapep; ++ *need_escapep = 0; ++ if (iswprint (w) && (!need_escape || (!iswdigit (w) ++ && w != L'8' ++ && w != L'9'))) ++ { ++ if (w == btowc (quoter) || w == L'\\') ++ obstack_grow_wstr (output, L"\\"); ++ obstack_grow (output, &w, sizeof (wchar_t)); ++ } ++ else ++ { ++ switch (w) ++ { ++ case L'\a': ++ obstack_grow_wstr (output, L"\\a"); ++ break; ++ case L'\b': ++ obstack_grow_wstr (output, L"\\b"); ++ break; ++ case L'\f': ++ obstack_grow_wstr (output, L"\\f"); ++ break; ++ case L'\n': ++ obstack_grow_wstr (output, L"\\n"); ++ break; ++ case L'\r': ++ obstack_grow_wstr (output, L"\\r"); ++ break; ++ case L'\t': ++ obstack_grow_wstr (output, L"\\t"); ++ break; ++ case L'\v': ++ obstack_grow_wstr (output, L"\\v"); ++ break; ++ default: ++ { ++ int i; ++ ++ for (i = 0; i + width <= orig_len; i += width) ++ { ++ char octal[30]; ++ ULONGEST value = extract_unsigned_integer (&orig[i], width); ++ sprintf (octal, "\\%lo", (long) value); ++ append_string_as_wide (octal, output); ++ } ++ /* If we somehow have extra bytes, print them now. */ ++ while (i < orig_len) ++ { ++ char octal[5]; ++ sprintf (octal, "\\%.3o", orig[i] & 0xff); ++ append_string_as_wide (octal, output); ++ ++i; ++ } ++ ++ *need_escapep = 1; ++ } ++ break; ++ } ++ } ++} + + /* Print the character C on STREAM as part of the contents of a literal + string whose delimiter is QUOTER. Note that that format for printing + characters and strings is language specific. */ + + static void +-c_emit_char (int c, struct ui_file *stream, int quoter) ++c_emit_char (int c, struct type *type, struct ui_file *stream, int quoter) + { +- const char *escape; +- int host_char; ++ struct obstack wchar_buf, output; ++ struct cleanup *cleanups; ++ const char *encoding; ++ gdb_byte *buf; ++ struct wchar_iterator *iter; ++ int need_escape = 0; + +- c &= 0xFF; /* Avoid sign bit follies */ ++ classify_type (type, &encoding); + +- escape = c_target_char_has_backslash_escape (c); +- if (escape) +- { +- if (quoter == '"' && strcmp (escape, "0") == 0) +- /* Print nulls embedded in double quoted strings as \000 to +- prevent ambiguity. */ +- fprintf_filtered (stream, "\\000"); +- else +- fprintf_filtered (stream, "\\%s", escape); +- } +- else if (target_char_to_host (c, &host_char) +- && host_char_print_literally (host_char)) ++ buf = alloca (TYPE_LENGTH (type)); ++ pack_long (buf, type, c); ++ ++ iter = make_wchar_iterator (buf, TYPE_LENGTH (type), encoding, ++ TYPE_LENGTH (type)); ++ cleanups = make_cleanup_wchar_iterator (iter); ++ ++ /* This holds the printable form of the wchar_t data. */ ++ obstack_init (&wchar_buf); ++ make_cleanup_obstack_free (&wchar_buf); ++ ++ while (1) + { +- if (host_char == '\\' || host_char == quoter) +- fputs_filtered ("\\", stream); +- fprintf_filtered (stream, "%c", host_char); ++ int num_chars; ++ wchar_t *chars; ++ const gdb_byte *buf; ++ size_t buflen; ++ int print_escape = 1; ++ enum wchar_iterate_result result; ++ ++ num_chars = wchar_iterate (iter, &result, &chars, &buf, &buflen); ++ if (num_chars < 0) ++ break; ++ if (num_chars > 0) ++ { ++ /* If all characters are printable, print them. Otherwise, ++ we're going to have to print an escape sequence. We ++ check all characters because we want to print the target ++ bytes in the escape sequence, and we don't know character ++ boundaries there. */ ++ int i; ++ ++ print_escape = 0; ++ for (i = 0; i < num_chars; ++i) ++ if (!wchar_printable (chars[i])) ++ { ++ print_escape = 1; ++ break; ++ } ++ ++ if (!print_escape) ++ { ++ for (i = 0; i < num_chars; ++i) ++ print_wchar (chars[i], buf, buflen, TYPE_LENGTH (type), ++ &wchar_buf, quoter, &need_escape); ++ } ++ } ++ ++ /* This handles the NUM_CHARS == 0 case as well. */ ++ if (print_escape) ++ print_wchar (WEOF, buf, buflen, TYPE_LENGTH (type), &wchar_buf, quoter, ++ &need_escape); + } +- else +- fprintf_filtered (stream, "\\%.3o", (unsigned int) c); ++ ++ /* The output in the host encoding. */ ++ obstack_init (&output); ++ make_cleanup_obstack_free (&output); ++ ++ convert_between_encodings ("wchar_t", host_charset (), ++ obstack_base (&wchar_buf), ++ obstack_object_size (&wchar_buf), ++ 1, &output, translit_char); ++ obstack_1grow (&output, '\0'); ++ ++ fputs_filtered (obstack_base (&output), stream); ++ ++ do_cleanups (cleanups); + } + + void +-c_printchar (int c, struct ui_file *stream) ++c_printchar (int c, struct type *type, struct ui_file *stream) + { ++ enum c_string_type str_type; ++ const char *encoding; ++ ++ str_type = classify_type (type, &encoding); ++ switch (str_type) ++ { ++ case C_CHAR: ++ break; ++ case C_WIDE_CHAR: ++ fputc_filtered ('L', stream); ++ break; ++ case C_CHAR_16: ++ fputc_filtered ('u', stream); ++ break; ++ case C_CHAR_32: ++ fputc_filtered ('U', stream); ++ break; ++ } ++ + fputc_filtered ('\'', stream); +- LA_EMIT_CHAR (c, stream, '\''); ++ LA_EMIT_CHAR (c, type, stream, '\''); + fputc_filtered ('\'', stream); + } + +@@ -85,87 +341,206 @@ c_printchar (int c, struct ui_file *stream) + printing LENGTH characters, or if FORCE_ELLIPSES. */ + + void +-c_printstr (struct ui_file *stream, const gdb_byte *string, +- unsigned int length, int width, int force_ellipses, ++c_printstr (struct ui_file *stream, struct type *type, const gdb_byte *string, ++ unsigned int length, int force_ellipses, + const struct value_print_options *options) + { + unsigned int i; + unsigned int things_printed = 0; + int in_quotes = 0; + int need_comma = 0; ++ int width = TYPE_LENGTH (type); ++ struct obstack wchar_buf, output; ++ struct cleanup *cleanup; ++ enum c_string_type str_type; ++ const char *encoding; ++ struct wchar_iterator *iter; ++ int finished = 0; ++ int need_escape = 0; + + /* If the string was not truncated due to `set print elements', and + the last byte of it is a null, we don't print that, in traditional C + style. */ + if (!force_ellipses + && length > 0 +- && (extract_unsigned_integer (string + (length - 1) * width, width) +- == '\0')) ++ && (extract_unsigned_integer (string + (length - 1) * width, width) == 0)) + length--; + ++ str_type = classify_type (type, &encoding) & ~C_CHAR; ++ switch (str_type) ++ { ++ case C_STRING: ++ break; ++ case C_WIDE_STRING: ++ fputs_filtered ("L", stream); ++ break; ++ case C_STRING_16: ++ fputs_filtered ("u", stream); ++ break; ++ case C_STRING_32: ++ fputs_filtered ("U", stream); ++ break; ++ } ++ + if (length == 0) + { + fputs_filtered ("\"\"", stream); + return; + } + +- for (i = 0; i < length && things_printed < options->print_max; ++i) ++ if (length == -1) ++ { ++ unsigned long current_char = 1; ++ for (i = 0; current_char; ++i) ++ { ++ QUIT; ++ current_char = extract_unsigned_integer (string + i * width, width); ++ } ++ length = i; ++ } ++ ++ /* Arrange to iterate over the characters, in wchar_t form. */ ++ iter = make_wchar_iterator (string, length * width, encoding, width); ++ cleanup = make_cleanup_wchar_iterator (iter); ++ ++ /* WCHAR_BUF is the obstack we use to represent the string in ++ wchar_t form. */ ++ obstack_init (&wchar_buf); ++ make_cleanup_obstack_free (&wchar_buf); ++ ++ while (!finished && things_printed < options->print_max) + { +- /* Position of the character we are examining +- to see whether it is repeated. */ +- unsigned int rep1; +- /* Number of repetitions we have detected so far. */ +- unsigned int reps; +- unsigned long current_char; ++ int num_chars; ++ enum wchar_iterate_result result; ++ wchar_t *chars; ++ const gdb_byte *buf; ++ size_t buflen; + + QUIT; + + if (need_comma) + { +- fputs_filtered (", ", stream); ++ obstack_grow_wstr (&wchar_buf, L", "); + need_comma = 0; + } + +- current_char = extract_unsigned_integer (string + i * width, width); ++ num_chars = wchar_iterate (iter, &result, &chars, &buf, &buflen); ++ /* We only look at repetitions when we were able to convert a ++ single character in isolation. This makes the code simpler ++ and probably does the sensible thing in the majority of ++ cases. */ ++ while (num_chars == 1) ++ { ++ /* Count the number of repetitions. */ ++ unsigned int reps = 0; ++ wchar_t current_char = chars[0]; ++ const gdb_byte *orig_buf = buf; ++ int orig_len = buflen; + +- rep1 = i + 1; +- reps = 1; +- while (rep1 < length +- && extract_unsigned_integer (string + rep1 * width, width) +- == current_char) ++ if (need_comma) ++ { ++ obstack_grow_wstr (&wchar_buf, L", "); ++ need_comma = 0; ++ } ++ ++ while (num_chars == 1 && current_char == chars[0]) ++ { ++ num_chars = wchar_iterate (iter, &result, &chars, &buf, &buflen); ++ ++reps; ++ } ++ ++ /* Emit CURRENT_CHAR according to the repetition count and ++ options. */ ++ if (reps > options->repeat_count_threshold) ++ { ++ if (in_quotes) ++ { ++ if (options->inspect_it) ++ obstack_grow_wstr (&wchar_buf, L"\\\", "); ++ else ++ obstack_grow_wstr (&wchar_buf, L"\", "); ++ in_quotes = 0; ++ } ++ obstack_grow_wstr (&wchar_buf, L"'"); ++ need_escape = 0; ++ print_wchar (current_char, orig_buf, orig_len, width, ++ &wchar_buf, '\'', &need_escape); ++ obstack_grow_wstr (&wchar_buf, L"'"); ++ { ++ /* Painful gyrations. */ ++ int j; ++ char *s = xstrprintf (_(" "), reps); ++ for (j = 0; s[j]; ++j) ++ { ++ wchar_t w = btowc (s[j]); ++ obstack_grow (&wchar_buf, &w, sizeof (wchar_t)); ++ } ++ xfree (s); ++ } ++ things_printed += options->repeat_count_threshold; ++ need_comma = 1; ++ } ++ else ++ { ++ /* Saw the character one or more times, but fewer than ++ the repetition threshold. */ ++ if (!in_quotes) ++ { ++ if (options->inspect_it) ++ obstack_grow_wstr (&wchar_buf, L"\\\""); ++ else ++ obstack_grow_wstr (&wchar_buf, L"\""); ++ in_quotes = 1; ++ need_escape = 0; ++ } ++ ++ while (reps-- > 0) ++ { ++ print_wchar (current_char, orig_buf, orig_len, width, ++ &wchar_buf, '"', &need_escape); ++ ++things_printed; ++ } ++ } ++ } ++ ++ /* NUM_CHARS and the other outputs from wchar_iterate are valid ++ here regardless of which branch was taken above. */ ++ if (num_chars < 0) + { +- ++rep1; +- ++reps; ++ /* Hit EOF. */ ++ finished = 1; ++ break; + } + +- if (reps > options->repeat_count_threshold) ++ switch (result) + { +- if (in_quotes) ++ case wchar_iterate_invalid: ++ if (!in_quotes) + { + if (options->inspect_it) +- fputs_filtered ("\\\", ", stream); ++ obstack_grow_wstr (&wchar_buf, L"\\\""); + else +- fputs_filtered ("\", ", stream); +- in_quotes = 0; ++ obstack_grow_wstr (&wchar_buf, L"\""); ++ in_quotes = 1; + } +- LA_PRINT_CHAR (current_char, stream); +- fprintf_filtered (stream, _(" "), reps); +- i = rep1 - 1; +- things_printed += options->repeat_count_threshold; +- need_comma = 1; +- } +- else +- { +- if (!in_quotes) ++ need_escape = 0; ++ print_wchar (WEOF, buf, buflen, width, &wchar_buf, '"', &need_escape); ++ break; ++ ++ case wchar_iterate_incomplete: ++ if (in_quotes) + { + if (options->inspect_it) +- fputs_filtered ("\\\"", stream); ++ obstack_grow_wstr (&wchar_buf, L"\\\","); + else +- fputs_filtered ("\"", stream); +- in_quotes = 1; ++ obstack_grow_wstr (&wchar_buf, L"\","); ++ in_quotes = 0; + } +- LA_EMIT_CHAR (current_char, stream, '"'); +- ++things_printed; ++ obstack_grow_wstr (&wchar_buf, L" "); ++ finished = 1; ++ break; + } + } + +@@ -173,13 +548,27 @@ c_printstr (struct ui_file *stream, const gdb_byte *string, + if (in_quotes) + { + if (options->inspect_it) +- fputs_filtered ("\\\"", stream); ++ obstack_grow_wstr (&wchar_buf, L"\\\""); + else +- fputs_filtered ("\"", stream); ++ obstack_grow_wstr (&wchar_buf, L"\""); + } + +- if (force_ellipses || i < length) +- fputs_filtered ("...", stream); ++ if (force_ellipses || !finished) ++ obstack_grow_wstr (&wchar_buf, L"..."); ++ ++ /* OUTPUT is where we collect `char's for printing. */ ++ obstack_init (&output); ++ make_cleanup_obstack_free (&output); ++ ++ convert_between_encodings ("wchar_t", host_charset (), ++ obstack_base (&wchar_buf), ++ obstack_object_size (&wchar_buf), ++ 1, &output, translit_char); ++ obstack_1grow (&output, '\0'); ++ ++ fputs_filtered (obstack_base (&output), stream); ++ ++ do_cleanups (cleanup); + } + + /* Obtain a C string from the inferior storing it in a newly allocated +@@ -298,7 +687,285 @@ c_get_string (struct value *value, gdb_byte **buffer, int *length, + } + + +-/* Preprocessing and parsing C and C++ expressions. */ ++/* Evaluating C and C++ expressions. */ ++ ++/* Convert a UCN. The digits of the UCN start at P and extend no ++ farther than LIMIT. DEST_CHARSET is the name of the character set ++ into which the UCN should be converted. The results are written to ++ OUTPUT. LENGTH is the maximum length of the UCN, either 4 or 8. ++ Returns a pointer to just after the final digit of the UCN. */ ++ ++static char * ++convert_ucn (char *p, char *limit, const char *dest_charset, ++ struct obstack *output, int length) ++{ ++ unsigned long result = 0; ++ gdb_byte data[4]; ++ int i; ++ ++ for (i = 0; i < length && p < limit && isxdigit (*p); ++i, ++p) ++ result = (result << 4) + host_hex_value (*p); ++ ++ for (i = 3; i >= 0; --i) ++ { ++ data[i] = result & 0xff; ++ result >>= 8; ++ } ++ ++ convert_between_encodings ("UCS-4BE", dest_charset, data, 4, 4, output, ++ translit_none); ++ ++ return p; ++} ++ ++/* Emit a character, VALUE, which was specified numerically, to ++ OUTPUT. TYPE is the target character type. */ ++ ++static void ++emit_numeric_character (struct type *type, unsigned long value, ++ struct obstack *output) ++{ ++ gdb_byte *buffer; ++ ++ buffer = alloca (TYPE_LENGTH (type)); ++ pack_long (buffer, type, value); ++ obstack_grow (output, buffer, TYPE_LENGTH (type)); ++} ++ ++/* Convert an octal escape sequence. TYPE is the target character ++ type. The digits of the escape sequence begin at P and extend no ++ farther than LIMIT. The result is written to OUTPUT. Returns a ++ pointer to just after the final digit of the escape sequence. */ ++ ++static char * ++convert_octal (struct type *type, char *p, char *limit, struct obstack *output) ++{ ++ unsigned long value = 0; ++ ++ while (p < limit && isdigit (*p) && *p != '8' && *p != '9') ++ { ++ value = 8 * value + host_hex_value (*p); ++ ++p; ++ } ++ ++ emit_numeric_character (type, value, output); ++ ++ return p; ++} ++ ++/* Convert a hex escape sequence. TYPE is the target character type. ++ The digits of the escape sequence begin at P and extend no farther ++ than LIMIT. The result is written to OUTPUT. Returns a pointer to ++ just after the final digit of the escape sequence. */ ++ ++static char * ++convert_hex (struct type *type, char *p, char *limit, struct obstack *output) ++{ ++ unsigned long value = 0; ++ ++ while (p < limit && isxdigit (*p)) ++ { ++ value = 16 * value + host_hex_value (*p); ++ ++p; ++ } ++ ++ emit_numeric_character (type, value, output); ++ ++ return p; ++} ++ ++#define ADVANCE \ ++ do { \ ++ ++p; \ ++ if (p == limit) \ ++ error (_("Malformed escape sequence")); \ ++ } while (0) ++ ++/* Convert an escape sequence to a target format. TYPE is the target ++ character type to use, and DEST_CHARSET is the name of the target ++ character set. The backslash of the escape sequence is at *P, and ++ the escape sequence will not extend past LIMIT. The results are ++ written to OUTPUT. Returns a pointer to just past the final ++ character of the escape sequence. */ ++ ++static char * ++convert_escape (struct type *type, const char *dest_charset, ++ char *p, char *limit, struct obstack *output) ++{ ++ /* Skip the backslash. */ ++ ADVANCE; ++ ++ switch (*p) ++ { ++ case '\\': ++ obstack_1grow (output, '\\'); ++ ++p; ++ break; ++ ++ case 'x': ++ ADVANCE; ++ if (!isxdigit (*p)) ++ error (_("\\x used with no following hex digits.")); ++ p = convert_hex (type, p, limit, output); ++ break; ++ ++ case '0': ++ case '1': ++ case '2': ++ case '3': ++ case '4': ++ case '5': ++ case '6': ++ case '7': ++ p = convert_octal (type, p, limit, output); ++ break; ++ ++ case 'u': ++ case 'U': ++ { ++ int length = *p == 'u' ? 4 : 8; ++ ADVANCE; ++ if (!isxdigit (*p)) ++ error (_("\\u used with no following hex digits")); ++ p = convert_ucn (p, limit, dest_charset, output, length); ++ } ++ } ++ ++ return p; ++} ++ ++/* Given a single string from a (C-specific) OP_STRING list, convert ++ it to a target string, handling escape sequences specially. The ++ output is written to OUTPUT. DATA is the input string, which has ++ length LEN. DEST_CHARSET is the name of the target character set, ++ and TYPE is the type of target character to use. */ ++ ++static void ++parse_one_string (struct obstack *output, char *data, int len, ++ const char *dest_charset, struct type *type) ++{ ++ char *limit; ++ ++ limit = data + len; ++ ++ while (data < limit) ++ { ++ char *p = data; ++ /* Look for next escape, or the end of the input. */ ++ while (p < limit && *p != '\\') ++ ++p; ++ /* If we saw a run of characters, convert them all. */ ++ if (p > data) ++ convert_between_encodings (host_charset (), dest_charset, ++ data, p - data, 1, output, translit_none); ++ /* If we saw an escape, convert it. */ ++ if (p < limit) ++ p = convert_escape (type, dest_charset, p, limit, output); ++ data = p; ++ } ++} ++ ++/* Expression evaluator for the C language family. Most operations ++ are delegated to evaluate_subexp_standard; see that function for a ++ description of the arguments. */ ++ ++static struct value * ++evaluate_subexp_c (struct type *expect_type, struct expression *exp, ++ int *pos, enum noside noside) ++{ ++ enum exp_opcode op = exp->elts[*pos].opcode; ++ ++ switch (op) ++ { ++ case OP_STRING: ++ { ++ int oplen, limit; ++ struct type *type; ++ struct obstack output; ++ struct cleanup *cleanup; ++ struct value *result; ++ enum c_string_type dest_type; ++ const char *dest_charset; ++ ++ obstack_init (&output); ++ cleanup = make_cleanup_obstack_free (&output); ++ ++ ++*pos; ++ oplen = longest_to_int (exp->elts[*pos].longconst); ++ ++ ++*pos; ++ limit = *pos + BYTES_TO_EXP_ELEM (oplen + 1); ++ dest_type ++ = (enum c_string_type) longest_to_int (exp->elts[*pos].longconst); ++ switch (dest_type & ~C_CHAR) ++ { ++ case C_STRING: ++ type = language_string_char_type (current_language, ++ current_gdbarch); ++ break; ++ case C_WIDE_STRING: ++ type = lookup_typename ("wchar_t", NULL, 0); ++ break; ++ case C_STRING_16: ++ type = lookup_typename ("char16_t", NULL, 0); ++ break; ++ case C_STRING_32: ++ type = lookup_typename ("char32_t", NULL, 0); ++ break; ++ default: ++ internal_error (__FILE__, __LINE__, "unhandled c_string_type"); ++ } ++ dest_charset = charset_for_string_type (dest_type); ++ ++ ++*pos; ++ while (*pos < limit) ++ { ++ int len; ++ ++ len = longest_to_int (exp->elts[*pos].longconst); ++ ++ ++*pos; ++ if (noside != EVAL_SKIP) ++ parse_one_string (&output, &exp->elts[*pos].string, len, ++ dest_charset, type); ++ *pos += BYTES_TO_EXP_ELEM (len); ++ } ++ ++ /* Skip the trailing length and opcode. */ ++ *pos += 2; ++ ++ if (noside == EVAL_SKIP) ++ return NULL; ++ ++ if ((dest_type & C_CHAR) != 0) ++ { ++ LONGEST value; ++ ++ if (obstack_object_size (&output) != TYPE_LENGTH (type)) ++ error (_("Could not convert character constant to target character set")); ++ value = unpack_long (type, obstack_base (&output)); ++ result = value_from_longest (type, value); ++ } ++ else ++ { ++ int i; ++ /* Write the terminating character. */ ++ for (i = 0; i < TYPE_LENGTH (type); ++i) ++ obstack_1grow (&output, 0); ++ result = value_typed_string (obstack_base (&output), ++ obstack_object_size (&output), ++ type); ++ } ++ do_cleanups (cleanup); ++ return result; ++ } ++ break; ++ ++ default: ++ break; ++ } ++ return evaluate_subexp_standard (expect_type, exp, pos, noside); ++} + + + +@@ -396,6 +1063,15 @@ c_language_arch_info (struct gdbarch *gdbarch, + lai->bool_type_default = builtin->builtin_int; + } + ++static const struct exp_descriptor exp_descriptor_c = ++{ ++ print_subexp_standard, ++ operator_length_standard, ++ op_name_standard, ++ dump_subexp_body_standard, ++ evaluate_subexp_c ++}; ++ + const struct language_defn c_language_defn = + { + "c", /* Language name */ +@@ -405,7 +1081,7 @@ const struct language_defn c_language_defn = + case_sensitive_on, + array_row_major, + macro_expansion_c, +- &exp_descriptor_standard, ++ &exp_descriptor_c, + c_parse, + c_error, + null_post_parser, +@@ -524,7 +1200,7 @@ const struct language_defn cplus_language_defn = + case_sensitive_on, + array_row_major, + macro_expansion_c, +- &exp_descriptor_standard, ++ &exp_descriptor_c, + c_parse, + c_error, + null_post_parser, +@@ -562,7 +1238,7 @@ const struct language_defn asm_language_defn = + case_sensitive_on, + array_row_major, + macro_expansion_c, +- &exp_descriptor_standard, ++ &exp_descriptor_c, + c_parse, + c_error, + null_post_parser, +@@ -605,7 +1281,7 @@ const struct language_defn minimal_language_defn = + case_sensitive_on, + array_row_major, + macro_expansion_c, +- &exp_descriptor_standard, ++ &exp_descriptor_c, + c_parse, + c_error, + null_post_parser, +diff --git a/gdb/c-lang.h b/gdb/c-lang.h +index 06c5767..ba9d996 100644 +--- a/gdb/c-lang.h ++++ b/gdb/c-lang.h +@@ -29,9 +29,38 @@ struct language_arch_info; + #include "macroexp.h" + + +-extern int c_parse (void); /* Defined in c-exp.y */ +- +-extern void c_error (char *); /* Defined in c-exp.y */ ++/* The various kinds of C string and character. Note that these ++ values are chosen so that they may be or'd together in certain ++ ways. */ ++enum c_string_type ++ { ++ /* An ordinary string: "value". */ ++ C_STRING = 0, ++ /* A wide string: L"value". */ ++ C_WIDE_STRING = 1, ++ /* A 16-bit Unicode string: u"value". */ ++ C_STRING_16 = 2, ++ /* A 32-bit Unicode string: U"value". */ ++ C_STRING_32 = 3, ++ /* An ordinary char: 'v'. This can also be or'd with one of the ++ above to form the corresponding CHAR value from a STRING ++ value. */ ++ C_CHAR = 4, ++ /* A wide char: L'v'. */ ++ C_WIDE_CHAR = 5, ++ /* A 16-bit Unicode char: u'v'. */ ++ C_CHAR_16 = 6, ++ /* A 32-bit Unicode char: U'v'. */ ++ C_CHAR_32 = 7 ++ }; ++ ++/* Defined in c-exp.y. */ ++ ++extern int c_parse (void); ++ ++extern void c_error (char *); ++ ++extern int c_parse_escape (char **, struct obstack *); + + /* Defined in c-typeprint.c */ + extern void c_print_type (struct type *, char *, struct ui_file *, int, +@@ -48,10 +77,10 @@ extern int c_value_print (struct value *, struct ui_file *, + + /* These are in c-lang.c: */ + +-extern void c_printchar (int, struct ui_file *); ++extern void c_printchar (int, struct type *, struct ui_file *); + +-extern void c_printstr (struct ui_file * stream, const gdb_byte *string, +- unsigned int length, int width, ++extern void c_printstr (struct ui_file * stream, struct type *elttype, ++ const gdb_byte *string, unsigned int length, + int force_ellipses, + const struct value_print_options *options); + +diff --git a/gdb/c-typeprint.c b/gdb/c-typeprint.c +index 0929516..c005fe4 100644 +--- a/gdb/c-typeprint.c ++++ b/gdb/c-typeprint.c +@@ -40,8 +40,6 @@ static void cp_type_print_method_args (struct type *mtype, char *prefix, + char *varstring, int staticp, + struct ui_file *stream); + +-static void c_type_print_args (struct type *, struct ui_file *); +- + static void cp_type_print_derivation_info (struct ui_file *, struct type *); + + static void c_type_print_varspec_prefix (struct type *, struct ui_file *, int, +@@ -199,6 +197,23 @@ cp_type_print_method_args (struct type *mtype, char *prefix, char *varstring, + fprintf_filtered (stream, "void"); + + fprintf_filtered (stream, ")"); ++ ++ /* For non-static methods, read qualifiers from the type of ++ THIS. */ ++ if (!staticp) ++ { ++ struct type *domain; ++ ++ gdb_assert (nargs > 0); ++ gdb_assert (TYPE_CODE (args[0].type) == TYPE_CODE_PTR); ++ domain = TYPE_TARGET_TYPE (args[0].type); ++ ++ if (TYPE_CONST (domain)) ++ fprintf_filtered (stream, " const"); ++ ++ if (TYPE_VOLATILE (domain)) ++ fprintf_filtered (stream, " volatile"); ++ } + } + + +@@ -354,10 +369,12 @@ c_type_print_modifier (struct type *type, struct ui_file *stream, + + /* Print out the arguments of TYPE, which should have TYPE_CODE_METHOD + or TYPE_CODE_FUNC, to STREAM. Artificial arguments, such as "this" +- in non-static methods, are displayed. */ ++ in non-static methods, are displayed if SHOW_ARTIFICIAL is ++ non-zero. */ + +-static void +-c_type_print_args (struct type *type, struct ui_file *stream) ++void ++c_type_print_args (struct type *type, struct ui_file *stream, ++ int show_artificial) + { + int i, len; + struct field *args; +@@ -369,6 +386,9 @@ c_type_print_args (struct type *type, struct ui_file *stream) + + for (i = 0; i < TYPE_NFIELDS (type); i++) + { ++ if (TYPE_FIELD_ARTIFICIAL (type, i) && !show_artificial) ++ continue; ++ + if (printed_any) + { + fprintf_filtered (stream, ", "); +@@ -559,7 +579,12 @@ c_type_print_varspec_suffix (struct type *type, struct ui_file *stream, + fprintf_filtered (stream, ")"); + + fprintf_filtered (stream, "["); +- if (TYPE_LENGTH (TYPE_TARGET_TYPE (type)) > 0 ++ if (TYPE_ARRAY_BOUND_IS_DWARF_BLOCK (type, 1)) ++ { ++ /* No _() - printed sources should not be locale dependent. */ ++ fprintf_filtered (stream, "variable"); ++ } ++ else if (TYPE_LENGTH (TYPE_TARGET_TYPE (type)) > 0 + && !TYPE_ARRAY_UPPER_BOUND_IS_UNDEFINED (type)) + fprintf_filtered (stream, "%d", + (TYPE_LENGTH (type) +@@ -592,7 +617,7 @@ c_type_print_varspec_suffix (struct type *type, struct ui_file *stream, + if (passed_a_ptr) + fprintf_filtered (stream, ")"); + if (!demangled_args) +- c_type_print_args (type, stream); ++ c_type_print_args (type, stream, 1); + c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, show, + passed_a_ptr, 0); + break; +diff --git a/gdb/c-valprint.c b/gdb/c-valprint.c +index 0b616f7..3433da2 100644 +--- a/gdb/c-valprint.c ++++ b/gdb/c-valprint.c +@@ -55,6 +55,18 @@ print_function_pointer_address (CORE_ADDR address, struct ui_file *stream, + } + + ++/* A helper for textual_element_type. This checks the name of the ++ typedef. This is bogus but it isn't apparent that the compiler ++ provides us the help we may need. */ ++ ++static int ++textual_name (const char *name) ++{ ++ return (!strcmp (name, "wchar_t") ++ || !strcmp (name, "char16_t") ++ || !strcmp (name, "char32_t")); ++} ++ + /* Apply a heuristic to decide whether an array of TYPE or a pointer + to TYPE should be printed as a textual string. Return non-zero if + it should, or zero if it should be treated as an array of integers +@@ -77,6 +89,15 @@ textual_element_type (struct type *type, char format) + /* TYPE_CODE_CHAR is always textual. */ + if (TYPE_CODE (true_type) == TYPE_CODE_CHAR) + return 1; ++ /* Any other character-like types must be integral. */ ++ if (TYPE_CODE (true_type) != TYPE_CODE_INT) ++ return 0; ++ ++ /* Check the names of the type and the typedef. */ ++ if (TYPE_NAME (type) && textual_name (TYPE_NAME (type))) ++ return 1; ++ if (TYPE_NAME (true_type) && textual_name (TYPE_NAME (true_type))) ++ return 1; + + if (format == 's') + { +@@ -115,7 +136,8 @@ c_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, + { + unsigned int i = 0; /* Number of characters printed */ + unsigned len; +- struct type *elttype; ++ struct type *elttype, *unresolved_elttype; ++ struct type *unresolved_type = type; + unsigned eltlen; + LONGEST val; + CORE_ADDR addr; +@@ -124,8 +146,9 @@ c_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, + switch (TYPE_CODE (type)) + { + case TYPE_CODE_ARRAY: +- elttype = check_typedef (TYPE_TARGET_TYPE (type)); +- if (TYPE_LENGTH (type) > 0 && TYPE_LENGTH (TYPE_TARGET_TYPE (type)) > 0) ++ unresolved_elttype = TYPE_TARGET_TYPE (type); ++ elttype = check_typedef (unresolved_elttype); ++ if (TYPE_LENGTH (type) > 0 && TYPE_LENGTH (unresolved_elttype) > 0) + { + eltlen = TYPE_LENGTH (elttype); + len = TYPE_LENGTH (type) / eltlen; +@@ -135,7 +158,7 @@ c_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, + } + + /* Print arrays of textual chars with a string syntax. */ +- if (textual_element_type (elttype, options->format)) ++ if (textual_element_type (unresolved_elttype, options->format)) + { + /* If requested, look for the first null char and only print + elements up to it. */ +@@ -143,15 +166,19 @@ c_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, + { + unsigned int temp_len; + +- /* Look for a NULL char. */ + for (temp_len = 0; +- (valaddr + embedded_offset)[temp_len] +- && temp_len < len && temp_len < options->print_max; +- temp_len++); ++ (temp_len < len ++ && temp_len < options->print_max ++ && extract_unsigned_integer (valaddr + embedded_offset ++ + temp_len * eltlen, ++ eltlen) == 0); ++ ++temp_len) ++ ; + len = temp_len; + } + +- LA_PRINT_STRING (stream, valaddr + embedded_offset, len, eltlen, 0, options); ++ LA_PRINT_STRING (stream, unresolved_elttype, ++ valaddr + embedded_offset, len, 0, options); + i = len; + } + else +@@ -209,7 +236,8 @@ c_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, + print_function_pointer_address (addr, stream, options->addressprint); + break; + } +- elttype = check_typedef (TYPE_TARGET_TYPE (type)); ++ unresolved_elttype = TYPE_TARGET_TYPE (type); ++ elttype = check_typedef (unresolved_elttype); + { + addr = unpack_pointer (type, valaddr + embedded_offset); + print_unpacked_pointer: +@@ -228,12 +256,11 @@ c_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, + + /* For a pointer to a textual type, also print the string + pointed to, unless pointer is null. */ +- /* FIXME: need to handle wchar_t here... */ + +- if (textual_element_type (elttype, options->format) ++ if (textual_element_type (unresolved_elttype, options->format) + && addr != 0) + { +- i = val_print_string (addr, -1, TYPE_LENGTH (elttype), stream, ++ i = val_print_string (unresolved_elttype, addr, -1, stream, + options); + } + else if (cp_is_vtbl_member (type)) +@@ -268,7 +295,7 @@ c_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, + } + else + { +- wtype = TYPE_TARGET_TYPE (type); ++ wtype = unresolved_elttype; + } + vt_val = value_at (wtype, vt_address); + common_val_print (vt_val, stream, recurse + 1, options, +@@ -442,11 +469,11 @@ c_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, + Since we don't know whether the value is really intended to + be used as an integer or a character, print the character + equivalent as well. */ +- if (textual_element_type (type, options->format)) ++ if (textual_element_type (unresolved_type, options->format)) + { + fputs_filtered (" ", stream); + LA_PRINT_CHAR ((unsigned char) unpack_long (type, valaddr + embedded_offset), +- stream); ++ unresolved_type, stream); + } + } + break; +@@ -468,7 +495,7 @@ c_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, + else + fprintf_filtered (stream, "%d", (int) val); + fputs_filtered (" ", stream); +- LA_PRINT_CHAR ((unsigned char) val, stream); ++ LA_PRINT_CHAR ((unsigned char) val, unresolved_type, stream); + } + break; + +@@ -540,7 +567,7 @@ int + c_value_print (struct value *val, struct ui_file *stream, + const struct value_print_options *options) + { +- struct type *type, *real_type; ++ struct type *type, *real_type, *val_type; + int full, top, using_enc; + struct value_print_options opts = *options; + +@@ -553,7 +580,11 @@ c_value_print (struct value *val, struct ui_file *stream, + C++: if it is a member pointer, we will take care + of that when we print it. */ + +- type = check_typedef (value_type (val)); ++ /* Preserve the original type before stripping typedefs. We prefer ++ to pass down the original type when possible, but for local ++ checks it is better to look past the typedefs. */ ++ val_type = value_type (val); ++ type = check_typedef (val_type); + + if (TYPE_CODE (type) == TYPE_CODE_PTR + || TYPE_CODE (type) == TYPE_CODE_REF) +@@ -561,11 +592,12 @@ c_value_print (struct value *val, struct ui_file *stream, + /* Hack: remove (char *) for char strings. Their + type is indicated by the quoted string anyway. + (Don't use textual_element_type here; quoted strings +- are always exactly (char *). */ +- if (TYPE_CODE (type) == TYPE_CODE_PTR +- && TYPE_NAME (type) == NULL +- && TYPE_NAME (TYPE_TARGET_TYPE (type)) != NULL +- && strcmp (TYPE_NAME (TYPE_TARGET_TYPE (type)), "char") == 0) ++ are always exactly (char *), (wchar_t *), or the like. */ ++ if (TYPE_CODE (val_type) == TYPE_CODE_PTR ++ && TYPE_NAME (val_type) == NULL ++ && TYPE_NAME (TYPE_TARGET_TYPE (val_type)) != NULL ++ && (strcmp (TYPE_NAME (TYPE_TARGET_TYPE (val_type)), "char") == 0 ++ || textual_name (TYPE_NAME (TYPE_TARGET_TYPE (val_type))))) + { + /* Print nothing */ + } +@@ -608,6 +640,7 @@ c_value_print (struct value *val, struct ui_file *stream, + } + type_print (type, "", stream, -1); + fprintf_filtered (stream, ") "); ++ val_type = type; + } + else + { +@@ -635,7 +668,7 @@ c_value_print (struct value *val, struct ui_file *stream, + /* Print out object: enclosing type is same as real_type if full */ + return val_print (value_enclosing_type (val), + value_contents_all (val), 0, +- VALUE_ADDRESS (val), stream, 0, ++ value_address (val), stream, 0, + &opts, current_language); + /* Note: When we look up RTTI entries, we don't get any information on + const or volatile attributes */ +@@ -647,14 +680,14 @@ c_value_print (struct value *val, struct ui_file *stream, + TYPE_NAME (value_enclosing_type (val))); + return val_print (value_enclosing_type (val), + value_contents_all (val), 0, +- VALUE_ADDRESS (val), stream, 0, ++ value_address (val), stream, 0, + &opts, current_language); + } + /* Otherwise, we end up at the return outside this "if" */ + } + +- return val_print (type, value_contents_all (val), ++ return val_print (val_type, value_contents_all (val), + value_embedded_offset (val), +- VALUE_ADDRESS (val) + value_offset (val), ++ value_address (val), + stream, 0, &opts, current_language); + } +diff --git a/gdb/charset-list.h b/gdb/charset-list.h +new file mode 100644 +index 0000000..59c64c5 +--- /dev/null ++++ b/gdb/charset-list.h +@@ -0,0 +1,1190 @@ ++/* List of character set names for GDB. ++ ++ Copyright (C) 2009 Free Software Foundation, Inc. ++ ++ This file is part of GDB. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++/* Note that the first entry must always be "auto". ++ The remaining entries were created by running this script: ++ ++ iconv -l | sed -e '/[/]...*$/d' -e 's@^\(.*\)//$@"\1", \\@' ++ ++ .. and then removing the final backslash. It would be nice to ++ separate narrow and wide character sets, but there is no good way ++ to do that. */ ++#define DEFAULT_CHARSET_NAMES \ ++"auto", \ ++"437", \ ++"500", \ ++"500V1", \ ++"850", \ ++"851", \ ++"852", \ ++"855", \ ++"856", \ ++"857", \ ++"860", \ ++"861", \ ++"862", \ ++"863", \ ++"864", \ ++"865", \ ++"866", \ ++"866NAV", \ ++"869", \ ++"874", \ ++"904", \ ++"1026", \ ++"1046", \ ++"1047", \ ++"8859_1", \ ++"8859_2", \ ++"8859_3", \ ++"8859_4", \ ++"8859_5", \ ++"8859_6", \ ++"8859_7", \ ++"8859_8", \ ++"8859_9", \ ++"10646-1:1993", \ ++"ANSI_X3.4-1968", \ ++"ANSI_X3.4-1986", \ ++"ANSI_X3.4", \ ++"ANSI_X3.110-1983", \ ++"ANSI_X3.110", \ ++"ARABIC", \ ++"ARABIC7", \ ++"ARMSCII-8", \ ++"ASCII", \ ++"ASMO-708", \ ++"ASMO_449", \ ++"BALTIC", \ ++"BIG-5", \ ++"BIG-FIVE", \ ++"BIG5-HKSCS", \ ++"BIG5", \ ++"BIG5HKSCS", \ ++"BIGFIVE", \ ++"BRF", \ ++"BS_4730", \ ++"CA", \ ++"CN-BIG5", \ ++"CN-GB", \ ++"CN", \ ++"CP-AR", \ ++"CP-GR", \ ++"CP-HU", \ ++"CP037", \ ++"CP038", \ ++"CP273", \ ++"CP274", \ ++"CP275", \ ++"CP278", \ ++"CP280", \ ++"CP281", \ ++"CP282", \ ++"CP284", \ ++"CP285", \ ++"CP290", \ ++"CP297", \ ++"CP367", \ ++"CP420", \ ++"CP423", \ ++"CP424", \ ++"CP437", \ ++"CP500", \ ++"CP737", \ ++"CP775", \ ++"CP803", \ ++"CP813", \ ++"CP819", \ ++"CP850", \ ++"CP851", \ ++"CP852", \ ++"CP855", \ ++"CP856", \ ++"CP857", \ ++"CP860", \ ++"CP861", \ ++"CP862", \ ++"CP863", \ ++"CP864", \ ++"CP865", \ ++"CP866", \ ++"CP866NAV", \ ++"CP868", \ ++"CP869", \ ++"CP870", \ ++"CP871", \ ++"CP874", \ ++"CP875", \ ++"CP880", \ ++"CP891", \ ++"CP901", \ ++"CP902", \ ++"CP903", \ ++"CP904", \ ++"CP905", \ ++"CP912", \ ++"CP915", \ ++"CP916", \ ++"CP918", \ ++"CP920", \ ++"CP921", \ ++"CP922", \ ++"CP930", \ ++"CP932", \ ++"CP933", \ ++"CP935", \ ++"CP936", \ ++"CP937", \ ++"CP939", \ ++"CP949", \ ++"CP950", \ ++"CP1004", \ ++"CP1008", \ ++"CP1025", \ ++"CP1026", \ ++"CP1046", \ ++"CP1047", \ ++"CP1070", \ ++"CP1079", \ ++"CP1081", \ ++"CP1084", \ ++"CP1089", \ ++"CP1097", \ ++"CP1112", \ ++"CP1122", \ ++"CP1123", \ ++"CP1124", \ ++"CP1125", \ ++"CP1129", \ ++"CP1130", \ ++"CP1132", \ ++"CP1133", \ ++"CP1137", \ ++"CP1140", \ ++"CP1141", \ ++"CP1142", \ ++"CP1143", \ ++"CP1144", \ ++"CP1145", \ ++"CP1146", \ ++"CP1147", \ ++"CP1148", \ ++"CP1149", \ ++"CP1153", \ ++"CP1154", \ ++"CP1155", \ ++"CP1156", \ ++"CP1157", \ ++"CP1158", \ ++"CP1160", \ ++"CP1161", \ ++"CP1162", \ ++"CP1163", \ ++"CP1164", \ ++"CP1166", \ ++"CP1167", \ ++"CP1250", \ ++"CP1251", \ ++"CP1252", \ ++"CP1253", \ ++"CP1254", \ ++"CP1255", \ ++"CP1256", \ ++"CP1257", \ ++"CP1258", \ ++"CP1282", \ ++"CP1361", \ ++"CP1364", \ ++"CP1371", \ ++"CP1388", \ ++"CP1390", \ ++"CP1399", \ ++"CP4517", \ ++"CP4899", \ ++"CP4909", \ ++"CP4971", \ ++"CP5347", \ ++"CP9030", \ ++"CP9066", \ ++"CP9448", \ ++"CP10007", \ ++"CP12712", \ ++"CP16804", \ ++"CPIBM861", \ ++"CSA7-1", \ ++"CSA7-2", \ ++"CSASCII", \ ++"CSA_T500-1983", \ ++"CSA_T500", \ ++"CSA_Z243.4-1985-1", \ ++"CSA_Z243.4-1985-2", \ ++"CSA_Z243.419851", \ ++"CSA_Z243.419852", \ ++"CSDECMCS", \ ++"CSEBCDICATDE", \ ++"CSEBCDICATDEA", \ ++"CSEBCDICCAFR", \ ++"CSEBCDICDKNO", \ ++"CSEBCDICDKNOA", \ ++"CSEBCDICES", \ ++"CSEBCDICESA", \ ++"CSEBCDICESS", \ ++"CSEBCDICFISE", \ ++"CSEBCDICFISEA", \ ++"CSEBCDICFR", \ ++"CSEBCDICIT", \ ++"CSEBCDICPT", \ ++"CSEBCDICUK", \ ++"CSEBCDICUS", \ ++"CSEUCKR", \ ++"CSEUCPKDFMTJAPANESE", \ ++"CSGB2312", \ ++"CSHPROMAN8", \ ++"CSIBM037", \ ++"CSIBM038", \ ++"CSIBM273", \ ++"CSIBM274", \ ++"CSIBM275", \ ++"CSIBM277", \ ++"CSIBM278", \ ++"CSIBM280", \ ++"CSIBM281", \ ++"CSIBM284", \ ++"CSIBM285", \ ++"CSIBM290", \ ++"CSIBM297", \ ++"CSIBM420", \ ++"CSIBM423", \ ++"CSIBM424", \ ++"CSIBM500", \ ++"CSIBM803", \ ++"CSIBM851", \ ++"CSIBM855", \ ++"CSIBM856", \ ++"CSIBM857", \ ++"CSIBM860", \ ++"CSIBM863", \ ++"CSIBM864", \ ++"CSIBM865", \ ++"CSIBM866", \ ++"CSIBM868", \ ++"CSIBM869", \ ++"CSIBM870", \ ++"CSIBM871", \ ++"CSIBM880", \ ++"CSIBM891", \ ++"CSIBM901", \ ++"CSIBM902", \ ++"CSIBM903", \ ++"CSIBM904", \ ++"CSIBM905", \ ++"CSIBM918", \ ++"CSIBM921", \ ++"CSIBM922", \ ++"CSIBM930", \ ++"CSIBM932", \ ++"CSIBM933", \ ++"CSIBM935", \ ++"CSIBM937", \ ++"CSIBM939", \ ++"CSIBM943", \ ++"CSIBM1008", \ ++"CSIBM1025", \ ++"CSIBM1026", \ ++"CSIBM1097", \ ++"CSIBM1112", \ ++"CSIBM1122", \ ++"CSIBM1123", \ ++"CSIBM1124", \ ++"CSIBM1129", \ ++"CSIBM1130", \ ++"CSIBM1132", \ ++"CSIBM1133", \ ++"CSIBM1137", \ ++"CSIBM1140", \ ++"CSIBM1141", \ ++"CSIBM1142", \ ++"CSIBM1143", \ ++"CSIBM1144", \ ++"CSIBM1145", \ ++"CSIBM1146", \ ++"CSIBM1147", \ ++"CSIBM1148", \ ++"CSIBM1149", \ ++"CSIBM1153", \ ++"CSIBM1154", \ ++"CSIBM1155", \ ++"CSIBM1156", \ ++"CSIBM1157", \ ++"CSIBM1158", \ ++"CSIBM1160", \ ++"CSIBM1161", \ ++"CSIBM1163", \ ++"CSIBM1164", \ ++"CSIBM1166", \ ++"CSIBM1167", \ ++"CSIBM1364", \ ++"CSIBM1371", \ ++"CSIBM1388", \ ++"CSIBM1390", \ ++"CSIBM1399", \ ++"CSIBM4517", \ ++"CSIBM4899", \ ++"CSIBM4909", \ ++"CSIBM4971", \ ++"CSIBM5347", \ ++"CSIBM9030", \ ++"CSIBM9066", \ ++"CSIBM9448", \ ++"CSIBM12712", \ ++"CSIBM16804", \ ++"CSIBM11621162", \ ++"CSISO4UNITEDKINGDOM", \ ++"CSISO10SWEDISH", \ ++"CSISO11SWEDISHFORNAMES", \ ++"CSISO14JISC6220RO", \ ++"CSISO15ITALIAN", \ ++"CSISO16PORTUGESE", \ ++"CSISO17SPANISH", \ ++"CSISO18GREEK7OLD", \ ++"CSISO19LATINGREEK", \ ++"CSISO21GERMAN", \ ++"CSISO25FRENCH", \ ++"CSISO27LATINGREEK1", \ ++"CSISO49INIS", \ ++"CSISO50INIS8", \ ++"CSISO51INISCYRILLIC", \ ++"CSISO58GB1988", \ ++"CSISO60DANISHNORWEGIAN", \ ++"CSISO60NORWEGIAN1", \ ++"CSISO61NORWEGIAN2", \ ++"CSISO69FRENCH", \ ++"CSISO84PORTUGUESE2", \ ++"CSISO85SPANISH2", \ ++"CSISO86HUNGARIAN", \ ++"CSISO88GREEK7", \ ++"CSISO89ASMO449", \ ++"CSISO90", \ ++"CSISO92JISC62991984B", \ ++"CSISO99NAPLPS", \ ++"CSISO103T618BIT", \ ++"CSISO111ECMACYRILLIC", \ ++"CSISO121CANADIAN1", \ ++"CSISO122CANADIAN2", \ ++"CSISO139CSN369103", \ ++"CSISO141JUSIB1002", \ ++"CSISO143IECP271", \ ++"CSISO150", \ ++"CSISO150GREEKCCITT", \ ++"CSISO151CUBA", \ ++"CSISO153GOST1976874", \ ++"CSISO646DANISH", \ ++"CSISO2022CN", \ ++"CSISO2022JP", \ ++"CSISO2022JP2", \ ++"CSISO2022KR", \ ++"CSISO2033", \ ++"CSISO5427CYRILLIC", \ ++"CSISO5427CYRILLIC1981", \ ++"CSISO5428GREEK", \ ++"CSISO10367BOX", \ ++"CSISOLATIN1", \ ++"CSISOLATIN2", \ ++"CSISOLATIN3", \ ++"CSISOLATIN4", \ ++"CSISOLATIN5", \ ++"CSISOLATIN6", \ ++"CSISOLATINARABIC", \ ++"CSISOLATINCYRILLIC", \ ++"CSISOLATINGREEK", \ ++"CSISOLATINHEBREW", \ ++"CSKOI8R", \ ++"CSKSC5636", \ ++"CSMACINTOSH", \ ++"CSNATSDANO", \ ++"CSNATSSEFI", \ ++"CSN_369103", \ ++"CSPC8CODEPAGE437", \ ++"CSPC775BALTIC", \ ++"CSPC850MULTILINGUAL", \ ++"CSPC862LATINHEBREW", \ ++"CSPCP852", \ ++"CSSHIFTJIS", \ ++"CSUCS4", \ ++"CSUNICODE", \ ++"CSWINDOWS31J", \ ++"CUBA", \ ++"CWI-2", \ ++"CWI", \ ++"CYRILLIC", \ ++"DE", \ ++"DEC-MCS", \ ++"DEC", \ ++"DECMCS", \ ++"DIN_66003", \ ++"DK", \ ++"DS2089", \ ++"DS_2089", \ ++"E13B", \ ++"EBCDIC-AT-DE-A", \ ++"EBCDIC-AT-DE", \ ++"EBCDIC-BE", \ ++"EBCDIC-BR", \ ++"EBCDIC-CA-FR", \ ++"EBCDIC-CP-AR1", \ ++"EBCDIC-CP-AR2", \ ++"EBCDIC-CP-BE", \ ++"EBCDIC-CP-CA", \ ++"EBCDIC-CP-CH", \ ++"EBCDIC-CP-DK", \ ++"EBCDIC-CP-ES", \ ++"EBCDIC-CP-FI", \ ++"EBCDIC-CP-FR", \ ++"EBCDIC-CP-GB", \ ++"EBCDIC-CP-GR", \ ++"EBCDIC-CP-HE", \ ++"EBCDIC-CP-IS", \ ++"EBCDIC-CP-IT", \ ++"EBCDIC-CP-NL", \ ++"EBCDIC-CP-NO", \ ++"EBCDIC-CP-ROECE", \ ++"EBCDIC-CP-SE", \ ++"EBCDIC-CP-TR", \ ++"EBCDIC-CP-US", \ ++"EBCDIC-CP-WT", \ ++"EBCDIC-CP-YU", \ ++"EBCDIC-CYRILLIC", \ ++"EBCDIC-DK-NO-A", \ ++"EBCDIC-DK-NO", \ ++"EBCDIC-ES-A", \ ++"EBCDIC-ES-S", \ ++"EBCDIC-ES", \ ++"EBCDIC-FI-SE-A", \ ++"EBCDIC-FI-SE", \ ++"EBCDIC-FR", \ ++"EBCDIC-GREEK", \ ++"EBCDIC-INT", \ ++"EBCDIC-INT1", \ ++"EBCDIC-IS-FRISS", \ ++"EBCDIC-IT", \ ++"EBCDIC-JP-E", \ ++"EBCDIC-JP-KANA", \ ++"EBCDIC-PT", \ ++"EBCDIC-UK", \ ++"EBCDIC-US", \ ++"EBCDICATDE", \ ++"EBCDICATDEA", \ ++"EBCDICCAFR", \ ++"EBCDICDKNO", \ ++"EBCDICDKNOA", \ ++"EBCDICES", \ ++"EBCDICESA", \ ++"EBCDICESS", \ ++"EBCDICFISE", \ ++"EBCDICFISEA", \ ++"EBCDICFR", \ ++"EBCDICISFRISS", \ ++"EBCDICIT", \ ++"EBCDICPT", \ ++"EBCDICUK", \ ++"EBCDICUS", \ ++"ECMA-114", \ ++"ECMA-118", \ ++"ECMA-128", \ ++"ECMA-CYRILLIC", \ ++"ECMACYRILLIC", \ ++"ELOT_928", \ ++"ES", \ ++"ES2", \ ++"EUC-CN", \ ++"EUC-JISX0213", \ ++"EUC-JP-MS", \ ++"EUC-JP", \ ++"EUC-KR", \ ++"EUC-TW", \ ++"EUCCN", \ ++"EUCJP-MS", \ ++"EUCJP-OPEN", \ ++"EUCJP-WIN", \ ++"EUCJP", \ ++"EUCKR", \ ++"EUCTW", \ ++"FI", \ ++"FR", \ ++"GB", \ ++"GB2312", \ ++"GB13000", \ ++"GB18030", \ ++"GBK", \ ++"GB_1988-80", \ ++"GB_198880", \ ++"GEORGIAN-ACADEMY", \ ++"GEORGIAN-PS", \ ++"GOST_19768-74", \ ++"GOST_19768", \ ++"GOST_1976874", \ ++"GREEK-CCITT", \ ++"GREEK", \ ++"GREEK7-OLD", \ ++"GREEK7", \ ++"GREEK7OLD", \ ++"GREEK8", \ ++"GREEKCCITT", \ ++"HEBREW", \ ++"HP-GREEK8", \ ++"HP-ROMAN8", \ ++"HP-ROMAN9", \ ++"HP-THAI8", \ ++"HP-TURKISH8", \ ++"HPGREEK8", \ ++"HPROMAN8", \ ++"HPROMAN9", \ ++"HPTHAI8", \ ++"HPTURKISH8", \ ++"HU", \ ++"IBM-803", \ ++"IBM-856", \ ++"IBM-901", \ ++"IBM-902", \ ++"IBM-921", \ ++"IBM-922", \ ++"IBM-930", \ ++"IBM-932", \ ++"IBM-933", \ ++"IBM-935", \ ++"IBM-937", \ ++"IBM-939", \ ++"IBM-943", \ ++"IBM-1008", \ ++"IBM-1025", \ ++"IBM-1046", \ ++"IBM-1047", \ ++"IBM-1097", \ ++"IBM-1112", \ ++"IBM-1122", \ ++"IBM-1123", \ ++"IBM-1124", \ ++"IBM-1129", \ ++"IBM-1130", \ ++"IBM-1132", \ ++"IBM-1133", \ ++"IBM-1137", \ ++"IBM-1140", \ ++"IBM-1141", \ ++"IBM-1142", \ ++"IBM-1143", \ ++"IBM-1144", \ ++"IBM-1145", \ ++"IBM-1146", \ ++"IBM-1147", \ ++"IBM-1148", \ ++"IBM-1149", \ ++"IBM-1153", \ ++"IBM-1154", \ ++"IBM-1155", \ ++"IBM-1156", \ ++"IBM-1157", \ ++"IBM-1158", \ ++"IBM-1160", \ ++"IBM-1161", \ ++"IBM-1162", \ ++"IBM-1163", \ ++"IBM-1164", \ ++"IBM-1166", \ ++"IBM-1167", \ ++"IBM-1364", \ ++"IBM-1371", \ ++"IBM-1388", \ ++"IBM-1390", \ ++"IBM-1399", \ ++"IBM-4517", \ ++"IBM-4899", \ ++"IBM-4909", \ ++"IBM-4971", \ ++"IBM-5347", \ ++"IBM-9030", \ ++"IBM-9066", \ ++"IBM-9448", \ ++"IBM-12712", \ ++"IBM-16804", \ ++"IBM037", \ ++"IBM038", \ ++"IBM256", \ ++"IBM273", \ ++"IBM274", \ ++"IBM275", \ ++"IBM277", \ ++"IBM278", \ ++"IBM280", \ ++"IBM281", \ ++"IBM284", \ ++"IBM285", \ ++"IBM290", \ ++"IBM297", \ ++"IBM367", \ ++"IBM420", \ ++"IBM423", \ ++"IBM424", \ ++"IBM437", \ ++"IBM500", \ ++"IBM775", \ ++"IBM803", \ ++"IBM813", \ ++"IBM819", \ ++"IBM848", \ ++"IBM850", \ ++"IBM851", \ ++"IBM852", \ ++"IBM855", \ ++"IBM856", \ ++"IBM857", \ ++"IBM860", \ ++"IBM861", \ ++"IBM862", \ ++"IBM863", \ ++"IBM864", \ ++"IBM865", \ ++"IBM866", \ ++"IBM866NAV", \ ++"IBM868", \ ++"IBM869", \ ++"IBM870", \ ++"IBM871", \ ++"IBM874", \ ++"IBM875", \ ++"IBM880", \ ++"IBM891", \ ++"IBM901", \ ++"IBM902", \ ++"IBM903", \ ++"IBM904", \ ++"IBM905", \ ++"IBM912", \ ++"IBM915", \ ++"IBM916", \ ++"IBM918", \ ++"IBM920", \ ++"IBM921", \ ++"IBM922", \ ++"IBM930", \ ++"IBM932", \ ++"IBM933", \ ++"IBM935", \ ++"IBM937", \ ++"IBM939", \ ++"IBM943", \ ++"IBM1004", \ ++"IBM1008", \ ++"IBM1025", \ ++"IBM1026", \ ++"IBM1046", \ ++"IBM1047", \ ++"IBM1089", \ ++"IBM1097", \ ++"IBM1112", \ ++"IBM1122", \ ++"IBM1123", \ ++"IBM1124", \ ++"IBM1129", \ ++"IBM1130", \ ++"IBM1132", \ ++"IBM1133", \ ++"IBM1137", \ ++"IBM1140", \ ++"IBM1141", \ ++"IBM1142", \ ++"IBM1143", \ ++"IBM1144", \ ++"IBM1145", \ ++"IBM1146", \ ++"IBM1147", \ ++"IBM1148", \ ++"IBM1149", \ ++"IBM1153", \ ++"IBM1154", \ ++"IBM1155", \ ++"IBM1156", \ ++"IBM1157", \ ++"IBM1158", \ ++"IBM1160", \ ++"IBM1161", \ ++"IBM1162", \ ++"IBM1163", \ ++"IBM1164", \ ++"IBM1166", \ ++"IBM1167", \ ++"IBM1364", \ ++"IBM1371", \ ++"IBM1388", \ ++"IBM1390", \ ++"IBM1399", \ ++"IBM4517", \ ++"IBM4899", \ ++"IBM4909", \ ++"IBM4971", \ ++"IBM5347", \ ++"IBM9030", \ ++"IBM9066", \ ++"IBM9448", \ ++"IBM12712", \ ++"IBM16804", \ ++"IEC_P27-1", \ ++"IEC_P271", \ ++"INIS-8", \ ++"INIS-CYRILLIC", \ ++"INIS", \ ++"INIS8", \ ++"INISCYRILLIC", \ ++"ISIRI-3342", \ ++"ISIRI3342", \ ++"ISO-2022-CN-EXT", \ ++"ISO-2022-CN", \ ++"ISO-2022-JP-2", \ ++"ISO-2022-JP-3", \ ++"ISO-2022-JP", \ ++"ISO-2022-KR", \ ++"ISO-8859-1", \ ++"ISO-8859-2", \ ++"ISO-8859-3", \ ++"ISO-8859-4", \ ++"ISO-8859-5", \ ++"ISO-8859-6", \ ++"ISO-8859-7", \ ++"ISO-8859-8", \ ++"ISO-8859-9", \ ++"ISO-8859-9E", \ ++"ISO-8859-10", \ ++"ISO-8859-11", \ ++"ISO-8859-13", \ ++"ISO-8859-14", \ ++"ISO-8859-15", \ ++"ISO-8859-16", \ ++"ISO-10646", \ ++"ISO-CELTIC", \ ++"ISO-IR-4", \ ++"ISO-IR-6", \ ++"ISO-IR-8-1", \ ++"ISO-IR-9-1", \ ++"ISO-IR-10", \ ++"ISO-IR-11", \ ++"ISO-IR-14", \ ++"ISO-IR-15", \ ++"ISO-IR-16", \ ++"ISO-IR-17", \ ++"ISO-IR-18", \ ++"ISO-IR-19", \ ++"ISO-IR-21", \ ++"ISO-IR-25", \ ++"ISO-IR-27", \ ++"ISO-IR-37", \ ++"ISO-IR-49", \ ++"ISO-IR-50", \ ++"ISO-IR-51", \ ++"ISO-IR-54", \ ++"ISO-IR-55", \ ++"ISO-IR-57", \ ++"ISO-IR-60", \ ++"ISO-IR-61", \ ++"ISO-IR-69", \ ++"ISO-IR-84", \ ++"ISO-IR-85", \ ++"ISO-IR-86", \ ++"ISO-IR-88", \ ++"ISO-IR-89", \ ++"ISO-IR-90", \ ++"ISO-IR-92", \ ++"ISO-IR-98", \ ++"ISO-IR-99", \ ++"ISO-IR-100", \ ++"ISO-IR-101", \ ++"ISO-IR-103", \ ++"ISO-IR-109", \ ++"ISO-IR-110", \ ++"ISO-IR-111", \ ++"ISO-IR-121", \ ++"ISO-IR-122", \ ++"ISO-IR-126", \ ++"ISO-IR-127", \ ++"ISO-IR-138", \ ++"ISO-IR-139", \ ++"ISO-IR-141", \ ++"ISO-IR-143", \ ++"ISO-IR-144", \ ++"ISO-IR-148", \ ++"ISO-IR-150", \ ++"ISO-IR-151", \ ++"ISO-IR-153", \ ++"ISO-IR-155", \ ++"ISO-IR-156", \ ++"ISO-IR-157", \ ++"ISO-IR-166", \ ++"ISO-IR-179", \ ++"ISO-IR-193", \ ++"ISO-IR-197", \ ++"ISO-IR-199", \ ++"ISO-IR-203", \ ++"ISO-IR-209", \ ++"ISO-IR-226", \ ++"ISO646-CA", \ ++"ISO646-CA2", \ ++"ISO646-CN", \ ++"ISO646-CU", \ ++"ISO646-DE", \ ++"ISO646-DK", \ ++"ISO646-ES", \ ++"ISO646-ES2", \ ++"ISO646-FI", \ ++"ISO646-FR", \ ++"ISO646-FR1", \ ++"ISO646-GB", \ ++"ISO646-HU", \ ++"ISO646-IT", \ ++"ISO646-JP-OCR-B", \ ++"ISO646-JP", \ ++"ISO646-KR", \ ++"ISO646-NO", \ ++"ISO646-NO2", \ ++"ISO646-PT", \ ++"ISO646-PT2", \ ++"ISO646-SE", \ ++"ISO646-SE2", \ ++"ISO646-US", \ ++"ISO646-YU", \ ++"ISO2022CN", \ ++"ISO2022CNEXT", \ ++"ISO2022JP", \ ++"ISO2022JP2", \ ++"ISO2022KR", \ ++"ISO6937", \ ++"ISO8859-1", \ ++"ISO8859-2", \ ++"ISO8859-3", \ ++"ISO8859-4", \ ++"ISO8859-5", \ ++"ISO8859-6", \ ++"ISO8859-7", \ ++"ISO8859-8", \ ++"ISO8859-9", \ ++"ISO8859-9E", \ ++"ISO8859-10", \ ++"ISO8859-11", \ ++"ISO8859-13", \ ++"ISO8859-14", \ ++"ISO8859-15", \ ++"ISO8859-16", \ ++"ISO11548-1", \ ++"ISO88591", \ ++"ISO88592", \ ++"ISO88593", \ ++"ISO88594", \ ++"ISO88595", \ ++"ISO88596", \ ++"ISO88597", \ ++"ISO88598", \ ++"ISO88599", \ ++"ISO88599E", \ ++"ISO885910", \ ++"ISO885911", \ ++"ISO885913", \ ++"ISO885914", \ ++"ISO885915", \ ++"ISO885916", \ ++"ISO_646.IRV:1991", \ ++"ISO_2033-1983", \ ++"ISO_2033", \ ++"ISO_5427-EXT", \ ++"ISO_5427", \ ++"ISO_5427:1981", \ ++"ISO_5427EXT", \ ++"ISO_5428", \ ++"ISO_5428:1980", \ ++"ISO_6937-2", \ ++"ISO_6937-2:1983", \ ++"ISO_6937", \ ++"ISO_6937:1992", \ ++"ISO_8859-1", \ ++"ISO_8859-1:1987", \ ++"ISO_8859-2", \ ++"ISO_8859-2:1987", \ ++"ISO_8859-3", \ ++"ISO_8859-3:1988", \ ++"ISO_8859-4", \ ++"ISO_8859-4:1988", \ ++"ISO_8859-5", \ ++"ISO_8859-5:1988", \ ++"ISO_8859-6", \ ++"ISO_8859-6:1987", \ ++"ISO_8859-7", \ ++"ISO_8859-7:1987", \ ++"ISO_8859-7:2003", \ ++"ISO_8859-8", \ ++"ISO_8859-8:1988", \ ++"ISO_8859-9", \ ++"ISO_8859-9:1989", \ ++"ISO_8859-9E", \ ++"ISO_8859-10", \ ++"ISO_8859-10:1992", \ ++"ISO_8859-14", \ ++"ISO_8859-14:1998", \ ++"ISO_8859-15", \ ++"ISO_8859-15:1998", \ ++"ISO_8859-16", \ ++"ISO_8859-16:2001", \ ++"ISO_9036", \ ++"ISO_10367-BOX", \ ++"ISO_10367BOX", \ ++"ISO_11548-1", \ ++"ISO_69372", \ ++"IT", \ ++"JIS_C6220-1969-RO", \ ++"JIS_C6229-1984-B", \ ++"JIS_C62201969RO", \ ++"JIS_C62291984B", \ ++"JOHAB", \ ++"JP-OCR-B", \ ++"JP", \ ++"JS", \ ++"JUS_I.B1.002", \ ++"KOI-7", \ ++"KOI-8", \ ++"KOI8-R", \ ++"KOI8-RU", \ ++"KOI8-T", \ ++"KOI8-U", \ ++"KOI8", \ ++"KOI8R", \ ++"KOI8U", \ ++"KSC5636", \ ++"L1", \ ++"L2", \ ++"L3", \ ++"L4", \ ++"L5", \ ++"L6", \ ++"L7", \ ++"L8", \ ++"L10", \ ++"LATIN-9", \ ++"LATIN-GREEK-1", \ ++"LATIN-GREEK", \ ++"LATIN1", \ ++"LATIN2", \ ++"LATIN3", \ ++"LATIN4", \ ++"LATIN5", \ ++"LATIN6", \ ++"LATIN7", \ ++"LATIN8", \ ++"LATIN10", \ ++"LATINGREEK", \ ++"LATINGREEK1", \ ++"MAC-CENTRALEUROPE", \ ++"MAC-CYRILLIC", \ ++"MAC-IS", \ ++"MAC-SAMI", \ ++"MAC-UK", \ ++"MAC", \ ++"MACCYRILLIC", \ ++"MACINTOSH", \ ++"MACIS", \ ++"MACUK", \ ++"MACUKRAINIAN", \ ++"MIK", \ ++"MS-ANSI", \ ++"MS-ARAB", \ ++"MS-CYRL", \ ++"MS-EE", \ ++"MS-GREEK", \ ++"MS-HEBR", \ ++"MS-MAC-CYRILLIC", \ ++"MS-TURK", \ ++"MS932", \ ++"MS936", \ ++"MSCP949", \ ++"MSCP1361", \ ++"MSMACCYRILLIC", \ ++"MSZ_7795.3", \ ++"MS_KANJI", \ ++"NAPLPS", \ ++"NATS-DANO", \ ++"NATS-SEFI", \ ++"NATSDANO", \ ++"NATSSEFI", \ ++"NC_NC0010", \ ++"NC_NC00-10", \ ++"NC_NC00-10:81", \ ++"NF_Z_62-010", \ ++"NF_Z_62-010_(1973)", \ ++"NF_Z_62-010_1973", \ ++"NF_Z_62010", \ ++"NF_Z_62010_1973", \ ++"NO", \ ++"NO2", \ ++"NS_4551-1", \ ++"NS_4551-2", \ ++"NS_45511", \ ++"NS_45512", \ ++"OS2LATIN1", \ ++"OSF00010001", \ ++"OSF00010002", \ ++"OSF00010003", \ ++"OSF00010004", \ ++"OSF00010005", \ ++"OSF00010006", \ ++"OSF00010007", \ ++"OSF00010008", \ ++"OSF00010009", \ ++"OSF0001000A", \ ++"OSF00010020", \ ++"OSF00010100", \ ++"OSF00010101", \ ++"OSF00010102", \ ++"OSF00010104", \ ++"OSF00010105", \ ++"OSF00010106", \ ++"OSF00030010", \ ++"OSF0004000A", \ ++"OSF0005000A", \ ++"OSF05010001", \ ++"OSF100201A4", \ ++"OSF100201A8", \ ++"OSF100201B5", \ ++"OSF100201F4", \ ++"OSF100203B5", \ ++"OSF1002011C", \ ++"OSF1002011D", \ ++"OSF1002035D", \ ++"OSF1002035E", \ ++"OSF1002035F", \ ++"OSF1002036B", \ ++"OSF1002037B", \ ++"OSF10010001", \ ++"OSF10010004", \ ++"OSF10010006", \ ++"OSF10020025", \ ++"OSF10020111", \ ++"OSF10020115", \ ++"OSF10020116", \ ++"OSF10020118", \ ++"OSF10020122", \ ++"OSF10020129", \ ++"OSF10020352", \ ++"OSF10020354", \ ++"OSF10020357", \ ++"OSF10020359", \ ++"OSF10020360", \ ++"OSF10020364", \ ++"OSF10020365", \ ++"OSF10020366", \ ++"OSF10020367", \ ++"OSF10020370", \ ++"OSF10020387", \ ++"OSF10020388", \ ++"OSF10020396", \ ++"OSF10020402", \ ++"OSF10020417", \ ++"PT", \ ++"PT2", \ ++"PT154", \ ++"R8", \ ++"R9", \ ++"RK1048", \ ++"ROMAN8", \ ++"ROMAN9", \ ++"RUSCII", \ ++"SE", \ ++"SE2", \ ++"SEN_850200_B", \ ++"SEN_850200_C", \ ++"SHIFT-JIS", \ ++"SHIFT_JIS", \ ++"SHIFT_JISX0213", \ ++"SJIS-OPEN", \ ++"SJIS-WIN", \ ++"SJIS", \ ++"SS636127", \ ++"STRK1048-2002", \ ++"ST_SEV_358-88", \ ++"T.61-8BIT", \ ++"T.61", \ ++"T.618BIT", \ ++"TCVN-5712", \ ++"TCVN", \ ++"TCVN5712-1", \ ++"TCVN5712-1:1993", \ ++"THAI8", \ ++"TIS-620", \ ++"TIS620-0", \ ++"TIS620.2529-1", \ ++"TIS620.2533-0", \ ++"TIS620", \ ++"TS-5881", \ ++"TSCII", \ ++"TURKISH8", \ ++"UCS-2", \ ++"UCS-2BE", \ ++"UCS-2LE", \ ++"UCS-4", \ ++"UCS-4BE", \ ++"UCS-4LE", \ ++"UCS2", \ ++"UCS4", \ ++"UHC", \ ++"UJIS", \ ++"UK", \ ++"UNICODE", \ ++"UNICODEBIG", \ ++"UNICODELITTLE", \ ++"US-ASCII", \ ++"US", \ ++"UTF-7", \ ++"UTF-8", \ ++"UTF-16", \ ++"UTF-16BE", \ ++"UTF-16LE", \ ++"UTF-32", \ ++"UTF-32BE", \ ++"UTF-32LE", \ ++"UTF7", \ ++"UTF8", \ ++"UTF16", \ ++"UTF16BE", \ ++"UTF16LE", \ ++"UTF32", \ ++"UTF32BE", \ ++"UTF32LE", \ ++"VISCII", \ ++"WCHAR_T", \ ++"WIN-SAMI-2", \ ++"WINBALTRIM", \ ++"WINDOWS-31J", \ ++"WINDOWS-874", \ ++"WINDOWS-936", \ ++"WINDOWS-1250", \ ++"WINDOWS-1251", \ ++"WINDOWS-1252", \ ++"WINDOWS-1253", \ ++"WINDOWS-1254", \ ++"WINDOWS-1255", \ ++"WINDOWS-1256", \ ++"WINDOWS-1257", \ ++"WINDOWS-1258", \ ++"WINSAMI2", \ ++"WS2", \ ++"YU", +diff --git a/gdb/charset.c b/gdb/charset.c +index 32eb9c3..4850fbf 100644 +--- a/gdb/charset.c ++++ b/gdb/charset.c +@@ -21,6 +21,9 @@ + #include "charset.h" + #include "gdbcmd.h" + #include "gdb_assert.h" ++#include "gdb_obstack.h" ++#include "charset-list.h" ++#include "vec.h" + + #include + #include "gdb_string.h" +@@ -33,15 +36,20 @@ + + /* How GDB's character set support works + +- GDB has two global settings: ++ GDB has three global settings: + + - The `current host character set' is the character set GDB should + use in talking to the user, and which (hopefully) the user's +- terminal knows how to display properly. ++ terminal knows how to display properly. Most users should not ++ change this. + + - The `current target character set' is the character set the + program being debugged uses. + ++ - The `current target wide character set' is the wide character set ++ the program being debugged uses, that is, the encoding used for ++ wchar_t. ++ + There are commands to set each of these, and mechanisms for + choosing reasonable default values. GDB has a global list of + character sets that it can use as its host or target character +@@ -57,118 +65,37 @@ + characters the user enters in expressions (mostly host->target + conversions), + +- and so on. +- +- Now, many of these operations are specific to a particular +- host/target character set pair. If GDB supports N character sets, +- there are N^2 possible pairs. This means that, the larger GDB's +- repertoire of character sets gets, the more expensive it gets to add +- new character sets. +- +- To make sure that GDB can do the right thing for every possible +- pairing of host and target character set, while still allowing +- GDB's repertoire to scale, we use a two-tiered approach: +- +- - We maintain a global table of "translations" --- groups of +- functions specific to a particular pair of character sets. +- +- - However, a translation can be incomplete: some functions can be +- omitted. Where there is not a translation to specify exactly +- what function to use, we provide reasonable defaults. The +- default behaviors try to use the "iconv" library functions, which +- support a wide range of character sets. However, even if iconv +- is not available, there are fallbacks to support trivial +- translations: when the host and target character sets are the +- same. */ +- +- +-/* The character set and translation structures. */ +- +- +-/* A character set GDB knows about. GDB only supports character sets +- with stateless encodings, in which every character is one byte +- long. */ +-struct charset { +- +- /* A singly-linked list of all known charsets. */ +- struct charset *next; +- +- /* The name of the character set. Comparisons on character set +- names are case-sensitive. */ +- const char *name; +- +- /* Non-zero iff this character set can be used as a host character +- set. At present, GDB basically assumes that the host character +- set is a superset of ASCII. */ +- int valid_host_charset; +- +- /* Pointers to charset-specific functions that depend only on a +- single character set, and data pointers to pass to them. */ +- int (*host_char_print_literally) (void *baton, +- int host_char); +- void *host_char_print_literally_baton; +- +- int (*target_char_to_control_char) (void *baton, +- int target_char, +- int *target_ctrl_char); +- void *target_char_to_control_char_baton; +-}; +- +- +-/* A translation from one character set to another. */ +-struct translation { +- +- /* A singly-linked list of all known translations. */ +- struct translation *next; +- +- /* This structure describes functions going from the FROM character +- set to the TO character set. Comparisons on character set names +- are case-sensitive. */ +- const char *from, *to; +- +- /* Pointers to translation-specific functions, and data pointers to +- pass to them. These pointers can be zero, indicating that GDB +- should fall back on the default behavior. We hope the default +- behavior will be correct for many from/to pairs, reducing the +- number of translations that need to be registered explicitly. */ +- +- /* TARGET_CHAR is in the `from' charset. +- Returns a string in the `to' charset. */ +- const char *(*c_target_char_has_backslash_escape) (void *baton, +- int target_char); +- void *c_target_char_has_backslash_escape_baton; +- +- /* HOST_CHAR is in the `from' charset. +- TARGET_CHAR points to a char in the `to' charset. */ +- int (*c_parse_backslash) (void *baton, int host_char, int *target_char); +- void *c_parse_backslash_baton; +- +- /* This is used for the host_char_to_target and target_char_to_host +- functions. */ +- int (*convert_char) (void *baton, int from, int *to); +- void *convert_char_baton; +-}; +- ++ and so on. ++ ++ To avoid excessive code duplication and maintenance efforts, ++ GDB simply requires a capable iconv function. Users on platforms ++ without a suitable iconv can use the GNU iconv library. */ + + + /* The global lists of character sets and translations. */ + + +-#ifndef GDB_DEFAULT_HOST_CHARSET +-#define GDB_DEFAULT_HOST_CHARSET "ISO-8859-1" +-#endif +- + #ifndef GDB_DEFAULT_TARGET_CHARSET + #define GDB_DEFAULT_TARGET_CHARSET "ISO-8859-1" + #endif + +-static const char *host_charset_name = GDB_DEFAULT_HOST_CHARSET; ++#ifndef GDB_DEFAULT_TARGET_WIDE_CHARSET ++#define GDB_DEFAULT_TARGET_WIDE_CHARSET "UCS-4" ++#endif ++ ++static const char *auto_host_charset_name = GDB_DEFAULT_HOST_CHARSET; ++static const char *host_charset_name = "auto"; + static void + show_host_charset_name (struct ui_file *file, int from_tty, + struct cmd_list_element *c, + const char *value) + { +- fprintf_filtered (file, _("The host character set is \"%s\".\n"), value); ++ if (!strcmp (value, "auto")) ++ fprintf_filtered (file, ++ _("The host character set is \"auto; currently %s\".\n"), ++ auto_host_charset_name); ++ else ++ fprintf_filtered (file, _("The host character set is \"%s\".\n"), value); + } + + static const char *target_charset_name = GDB_DEFAULT_TARGET_CHARSET; +@@ -180,1060 +107,534 @@ show_target_charset_name (struct ui_file *file, int from_tty, + value); + } + +- +-static const char *host_charset_enum[] = ++static const char *target_wide_charset_name = GDB_DEFAULT_TARGET_WIDE_CHARSET; ++static void ++show_target_wide_charset_name (struct ui_file *file, int from_tty, ++ struct cmd_list_element *c, const char *value) + { +- "ASCII", +- "ISO-8859-1", +- 0 +-}; ++ fprintf_filtered (file, _("The target wide character set is \"%s\".\n"), ++ value); ++} + +-static const char *target_charset_enum[] = ++static const char *default_charset_names[] = + { +- "ASCII", +- "ISO-8859-1", +- "EBCDIC-US", +- "IBM1047", ++ DEFAULT_CHARSET_NAMES + 0 + }; + +-/* The global list of all the charsets GDB knows about. */ +-static struct charset *all_charsets; ++static const char **charset_enum; + ++ ++/* If the target wide character set has big- or little-endian ++ variants, these are the corresponding names. */ ++static const char *target_wide_charset_be_name; ++static const char *target_wide_charset_le_name; + +-static void +-register_charset (struct charset *cs) +-{ +- struct charset **ptr; +- +- /* Put the new charset on the end, so that the list ends up in the +- same order as the registrations in the _initialize function. */ +- for (ptr = &all_charsets; *ptr; ptr = &(*ptr)->next) +- ; +- +- cs->next = 0; +- *ptr = cs; +-} +- ++/* A helper function for validate which sets the target wide big- and ++ little-endian character set names, if possible. */ + +-static struct charset * +-lookup_charset (const char *name) ++static void ++set_be_le_names (void) + { +- struct charset *cs; ++ int i, len; + +- for (cs = all_charsets; cs; cs = cs->next) +- if (! strcmp (name, cs->name)) +- return cs; ++ target_wide_charset_le_name = NULL; ++ target_wide_charset_be_name = NULL; + +- return NULL; ++ len = strlen (target_wide_charset_name); ++ for (i = 0; charset_enum[i]; ++i) ++ { ++ if (strncmp (target_wide_charset_name, charset_enum[i], len)) ++ continue; ++ if ((charset_enum[i][len] == 'B' ++ || charset_enum[i][len] == 'L') ++ && charset_enum[i][len + 1] == 'E' ++ && charset_enum[i][len + 2] == '\0') ++ { ++ if (charset_enum[i][len] == 'B') ++ target_wide_charset_be_name = charset_enum[i]; ++ else ++ target_wide_charset_le_name = charset_enum[i]; ++ } ++ } + } + +- +-/* The global list of translations. */ +-static struct translation *all_translations; +- ++/* 'Set charset', 'set host-charset', 'set target-charset', 'set ++ target-wide-charset', 'set charset' sfunc's. */ + + static void +-register_translation (struct translation *t) ++validate (void) + { +- t->next = all_translations; +- all_translations = t; +-} +- +- +-static struct translation * +-lookup_translation (const char *from, const char *to) +-{ +- struct translation *t; +- +- for (t = all_translations; t; t = t->next) +- if (! strcmp (from, t->from) +- && ! strcmp (to, t->to)) +- return t; ++ iconv_t desc; ++ const char *host_cset = host_charset (); + +- return 0; +-} +- +- +- +-/* Constructing charsets. */ +- +-/* Allocate, initialize and return a straightforward charset. +- Use this function, rather than creating the structures yourself, +- so that we can add new fields to the structure in the future without +- having to tweak all the old charset descriptions. */ +-static struct charset * +-simple_charset (const char *name, +- int valid_host_charset, +- int (*host_char_print_literally) (void *baton, int host_char), +- void *host_char_print_literally_baton, +- int (*target_char_to_control_char) (void *baton, +- int target_char, +- int *target_ctrl_char), +- void *target_char_to_control_char_baton) +-{ +- struct charset *cs = xmalloc (sizeof (*cs)); ++ desc = iconv_open (target_wide_charset_name, host_cset); ++ if (desc == (iconv_t) -1) ++ error ("Cannot convert between character sets `%s' and `%s'", ++ target_wide_charset_name, host_cset); ++ iconv_close (desc); + +- memset (cs, 0, sizeof (*cs)); +- cs->name = name; +- cs->valid_host_charset = valid_host_charset; +- cs->host_char_print_literally = host_char_print_literally; +- cs->host_char_print_literally_baton = host_char_print_literally_baton; +- cs->target_char_to_control_char = target_char_to_control_char; +- cs->target_char_to_control_char_baton = target_char_to_control_char_baton; ++ desc = iconv_open (target_charset_name, host_cset); ++ if (desc == (iconv_t) -1) ++ error ("Cannot convert between character sets `%s' and `%s'", ++ target_charset_name, host_cset); ++ iconv_close (desc); + +- return cs; ++ set_be_le_names (); + } + +- +- +-/* ASCII functions. */ +- +-static int +-ascii_print_literally (void *baton, int c) ++/* This is the sfunc for the 'set charset' command. */ ++static void ++set_charset_sfunc (char *charset, int from_tty, struct cmd_list_element *c) + { +- c &= 0xff; +- +- return (0x20 <= c && c <= 0x7e); ++ /* CAREFUL: set the target charset here as well. */ ++ target_charset_name = host_charset_name; ++ validate (); + } + +- +-static int +-ascii_to_control (void *baton, int c, int *ctrl_char) ++/* 'set host-charset' command sfunc. We need a wrapper here because ++ the function needs to have a specific signature. */ ++static void ++set_host_charset_sfunc (char *charset, int from_tty, ++ struct cmd_list_element *c) + { +- *ctrl_char = (c & 037); +- return 1; ++ validate (); + } + +- +-/* ISO-8859 family functions. */ +- +- +-static int +-iso_8859_print_literally (void *baton, int c) ++/* Wrapper for the 'set target-charset' command. */ ++static void ++set_target_charset_sfunc (char *charset, int from_tty, ++ struct cmd_list_element *c) + { +- c &= 0xff; +- +- return ((0x20 <= c && c <= 0x7e) /* ascii printables */ +- || (! sevenbit_strings && 0xA0 <= c)); /* iso 8859 printables */ ++ validate (); + } + +- +-static int +-iso_8859_to_control (void *baton, int c, int *ctrl_char) ++/* Wrapper for the 'set target-wide-charset' command. */ ++static void ++set_target_wide_charset_sfunc (char *charset, int from_tty, ++ struct cmd_list_element *c) + { +- *ctrl_char = (c & 0200) | (c & 037); +- return 1; ++ validate (); + } + +- +-/* Construct an ISO-8859-like character set. */ +-static struct charset * +-iso_8859_family_charset (const char *name) ++/* sfunc for the 'show charset' command. */ ++static void ++show_charset (struct ui_file *file, int from_tty, struct cmd_list_element *c, ++ const char *name) + { +- return simple_charset (name, 1, +- iso_8859_print_literally, 0, +- iso_8859_to_control, 0); ++ show_host_charset_name (file, from_tty, c, host_charset_name); ++ show_target_charset_name (file, from_tty, c, target_charset_name); ++ show_target_wide_charset_name (file, from_tty, c, target_wide_charset_name); + } + +- + +-/* EBCDIC family functions. */ +- +- +-static int +-ebcdic_print_literally (void *baton, int c) +-{ +- c &= 0xff; +- +- return (64 <= c && c <= 254); +-} +- ++/* Accessor functions. */ + +-static int +-ebcdic_to_control (void *baton, int c, int *ctrl_char) ++const char * ++host_charset (void) + { +- /* There are no control character equivalents in EBCDIC. Use +- numeric escapes. */ +- return 0; ++ if (!strcmp (host_charset_name, "auto")) ++ return auto_host_charset_name; ++ return host_charset_name; + } + +- +-/* Construct an EBCDIC-like character set. */ +-static struct charset * +-ebcdic_family_charset (const char *name) ++const char * ++target_charset (void) + { +- return simple_charset (name, 0, +- ebcdic_print_literally, 0, +- ebcdic_to_control, 0); ++ return target_charset_name; + } +- +- +- +- +- +-/* Fallback functions using iconv. */ +- +-#if defined(HAVE_ICONV) + +-struct cached_iconv { +- struct charset *from, *to; +- iconv_t i; +-}; +- +- +-/* Make sure the iconv cache *CI contains an iconv descriptor +- translating from FROM to TO. If it already does, fine; otherwise, +- close any existing descriptor, and open up a new one. On success, +- return zero; on failure, return -1 and set errno. */ +-static int +-check_iconv_cache (struct cached_iconv *ci, +- struct charset *from, +- struct charset *to) ++const char * ++target_wide_charset (void) + { +- iconv_t i; +- +- /* Does the cached iconv descriptor match the conversion we're trying +- to do now? */ +- if (ci->from == from +- && ci->to == to +- && ci->i != (iconv_t) 0) +- return 0; +- +- /* It doesn't. If we actually had any iconv descriptor open at +- all, close it now. */ +- if (ci->i != (iconv_t) 0) ++ if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG) + { +- i = ci->i; +- ci->i = (iconv_t) 0; +- +- if (iconv_close (i) == -1) +- error (_("Error closing `iconv' descriptor for " +- "`%s'-to-`%s' character conversion: %s"), +- ci->from->name, ci->to->name, safe_strerror (errno)); ++ if (target_wide_charset_be_name) ++ return target_wide_charset_be_name; + } +- +- /* Open a new iconv descriptor for the required conversion. */ +- i = iconv_open (to->name, from->name); +- if (i == (iconv_t) -1) +- return -1; +- +- ci->i = i; +- ci->from = from; +- ci->to = to; +- +- return 0; +-} +- +- +-/* Convert FROM_CHAR using the cached iconv conversion *CI. Return +- non-zero if the conversion was successful, zero otherwise. */ +-static int +-cached_iconv_convert (struct cached_iconv *ci, int from_char, int *to_char) +-{ +- char from; +- ICONV_CONST char *from_ptr = &from; +- char to, *to_ptr = &to; +- size_t from_left = sizeof (from), to_left = sizeof (to); +- +- gdb_assert (ci->i != (iconv_t) 0); +- +- from = from_char; +- if (iconv (ci->i, &from_ptr, &from_left, &to_ptr, &to_left) +- == (size_t) -1) ++ else + { +- /* These all suggest that the input or output character sets +- have multi-byte encodings of some characters, which means +- it's unsuitable for use as a GDB character set. We should +- never have selected it. */ +- gdb_assert (errno != E2BIG && errno != EINVAL); +- +- /* This suggests a bug in the code managing *CI. */ +- gdb_assert (errno != EBADF); +- +- /* This seems to mean that there is no equivalent character in +- the `to' character set. */ +- if (errno == EILSEQ) +- return 0; +- +- /* Anything else is mysterious. */ +- internal_error (__FILE__, __LINE__, +- _("Error converting character `%d' from `%s' to `%s' " +- "character set: %s"), +- from_char, ci->from->name, ci->to->name, +- safe_strerror (errno)); ++ if (target_wide_charset_le_name) ++ return target_wide_charset_le_name; + } + +- /* If the pointers weren't advanced across the input, that also +- suggests something was wrong. */ +- gdb_assert (from_left == 0 && to_left == 0); +- +- *to_char = (unsigned char) to; +- return 1; ++ return target_wide_charset_name; + } + +- +-static void +-register_iconv_charsets (void) +-{ +- /* Here we should check whether various character sets were +- recognized by the local iconv implementation. +- +- The first implementation registered a bunch of character sets +- recognized by iconv, but then we discovered that iconv on Solaris +- and iconv on GNU/Linux had no character sets in common. So we +- replaced them with the hard-coded tables that appear later in the +- file. */ +-} +- +-#endif /* defined (HAVE_ICONV) */ +- + +-/* Fallback routines for systems without iconv. */ ++/* Host character set management. For the time being, we assume that ++ the host character set is some superset of ASCII. */ + +-#if ! defined (HAVE_ICONV) +-struct cached_iconv { char nothing; }; +- +-static int +-check_iconv_cache (struct cached_iconv *ci, +- struct charset *from, +- struct charset *to) ++char ++host_letter_to_control_character (char c) + { +- errno = EINVAL; +- return -1; ++ if (c == '?') ++ return 0177; ++ return c & 0237; + } + +-static int +-cached_iconv_convert (struct cached_iconv *ci, int from_char, int *to_char) +-{ +- /* This function should never be called. */ +- gdb_assert (0); +-} ++/* Convert a host character, C, to its hex value. C must already have ++ been validated using isxdigit. */ + +-static void +-register_iconv_charsets (void) +-{ +-} +- +-#endif /* ! defined(HAVE_ICONV) */ +- +- +-/* Default trivial conversion functions. */ +- +-static int +-identity_either_char_to_other (void *baton, int either_char, int *other_char) ++int ++host_hex_value (char c) + { +- *other_char = either_char; +- return 1; ++ if (isdigit (c)) ++ return c - '0'; ++ if (c >= 'a' && c <= 'f') ++ return 10 + c - 'a'; ++ gdb_assert (c >= 'A' && c <= 'F'); ++ return 10 + c - 'A'; + } + +- + +-/* Default non-trivial conversion functions. */ +- +- +-static char backslashable[] = "abfnrtv"; +-static char *backslashed[] = {"a", "b", "f", "n", "r", "t", "v", "0"}; +-static char represented[] = "\a\b\f\n\r\t\v"; +- +- +-/* Translate TARGET_CHAR into the host character set, and see if it +- matches any of our standard escape sequences. */ +-static const char * +-default_c_target_char_has_backslash_escape (void *baton, int target_char) +-{ +- int host_char; +- const char *ix; +- +- /* If target_char has no equivalent in the host character set, +- assume it doesn't have a backslashed form. */ +- if (! target_char_to_host (target_char, &host_char)) +- return NULL; +- +- ix = strchr (represented, host_char); +- if (ix) +- return backslashed[ix - represented]; +- else +- return NULL; +-} +- +- +-/* Translate the backslash the way we would in the host character set, +- and then try to translate that into the target character set. */ +-static int +-default_c_parse_backslash (void *baton, int host_char, int *target_char) +-{ +- const char *ix; +- +- ix = strchr (backslashable, host_char); +- +- if (! ix) +- return 0; +- else +- return host_char_to_target (represented[ix - backslashable], +- target_char); +-} ++/* Public character management functions. */ + ++/* A cleanup function which is run to close an iconv descriptor. */ + +-/* Convert using a cached iconv descriptor. */ +-static int +-iconv_convert (void *baton, int from_char, int *to_char) ++static void ++cleanup_iconv (void *p) + { +- struct cached_iconv *ci = baton; +- return cached_iconv_convert (ci, from_char, to_char); ++ iconv_t *descp = p; ++ iconv_close (*descp); + } + ++void ++convert_between_encodings (const char *from, const char *to, ++ const gdb_byte *bytes, unsigned int num_bytes, ++ int width, struct obstack *output, ++ enum transliterations translit) ++{ ++ iconv_t desc; ++ struct cleanup *cleanups; ++ size_t inleft; ++ char *inp; ++ unsigned int space_request; ++ ++ /* Often, the host and target charsets will be the same. */ ++ if (!strcmp (from, to)) ++ { ++ obstack_grow (output, bytes, num_bytes); ++ return; ++ } + +- +-/* Conversion tables. */ +- +- +-/* I'd much rather fall back on iconv whenever possible. But the +- character set names you use with iconv aren't standardized at all, +- a lot of platforms have really meager character set coverage, etc. +- I wanted to have at least something we could use to exercise the +- test suite on all platforms. +- +- In the long run, we should have a configure-time process explore +- somehow which character sets the host platform supports, and some +- arrangement that allows GDB users to use platform-indepedent names +- for character sets. */ +- +- +-/* We generated these tables using iconv on a GNU/Linux machine. */ +- +- +-static int ascii_to_iso_8859_1_table[] = { +- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 16 */ +- 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, /* 32 */ +- 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, /* 48 */ +- 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, /* 64 */ +- 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, /* 80 */ +- 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, /* 96 */ +- 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, /* 112 */ +- 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, /* 128 */ +- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 144 */ +- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 160 */ +- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 176 */ +- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 192 */ +- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 208 */ +- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 224 */ +- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 240 */ +- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 256 */ +-}; +- +- +-static int ascii_to_ebcdic_us_table[] = { +- 0, 1, 2, 3, 55, 45, 46, 47, 22, 5, 37, 11, 12, 13, 14, 15, /* 16 */ +- 16, 17, 18, 19, 60, 61, 50, 38, 24, 25, 63, 39, 28, 29, 30, 31, /* 32 */ +- 64, 90,127,123, 91,108, 80,125, 77, 93, 92, 78,107, 96, 75, 97, /* 48 */ +- 240,241,242,243,244,245,246,247,248,249,122, 94, 76,126,110,111, /* 64 */ +- 124,193,194,195,196,197,198,199,200,201,209,210,211,212,213,214, /* 80 */ +- 215,216,217,226,227,228,229,230,231,232,233, -1,224, -1, -1,109, /* 96 */ +- 121,129,130,131,132,133,134,135,136,137,145,146,147,148,149,150, /* 112 */ +- 151,152,153,162,163,164,165,166,167,168,169,192, 79,208,161, 7, /* 128 */ +- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 144 */ +- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 160 */ +- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 176 */ +- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 192 */ +- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 208 */ +- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 224 */ +- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 240 */ +- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 256 */ +-}; +- +- +-static int ascii_to_ibm1047_table[] = { +- 0, 1, 2, 3, 55, 45, 46, 47, 22, 5, 37, 11, 12, 13, 14, 15, /* 16 */ +- 16, 17, 18, 19, 60, 61, 50, 38, 24, 25, 63, 39, 28, 29, 30, 31, /* 32 */ +- 64, 90,127,123, 91,108, 80,125, 77, 93, 92, 78,107, 96, 75, 97, /* 48 */ +- 240,241,242,243,244,245,246,247,248,249,122, 94, 76,126,110,111, /* 64 */ +- 124,193,194,195,196,197,198,199,200,201,209,210,211,212,213,214, /* 80 */ +- 215,216,217,226,227,228,229,230,231,232,233,173,224,189, 95,109, /* 96 */ +- 121,129,130,131,132,133,134,135,136,137,145,146,147,148,149,150, /* 112 */ +- 151,152,153,162,163,164,165,166,167,168,169,192, 79,208,161, 7, /* 128 */ +- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 144 */ +- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 160 */ +- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 176 */ +- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 192 */ +- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 208 */ +- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 224 */ +- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 240 */ +- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 256 */ +-}; +- +- +-static int iso_8859_1_to_ascii_table[] = { +- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 16 */ +- 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, /* 32 */ +- 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, /* 48 */ +- 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, /* 64 */ +- 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, /* 80 */ +- 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, /* 96 */ +- 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, /* 112 */ +- 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, /* 128 */ +- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 144 */ +- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 160 */ +- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 176 */ +- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 192 */ +- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 208 */ +- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 224 */ +- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 240 */ +- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 256 */ +-}; +- +- +-static int iso_8859_1_to_ebcdic_us_table[] = { +- 0, 1, 2, 3, 55, 45, 46, 47, 22, 5, 37, 11, 12, 13, 14, 15, /* 16 */ +- 16, 17, 18, 19, 60, 61, 50, 38, 24, 25, 63, 39, 28, 29, 30, 31, /* 32 */ +- 64, 90,127,123, 91,108, 80,125, 77, 93, 92, 78,107, 96, 75, 97, /* 48 */ +- 240,241,242,243,244,245,246,247,248,249,122, 94, 76,126,110,111, /* 64 */ +- 124,193,194,195,196,197,198,199,200,201,209,210,211,212,213,214, /* 80 */ +- 215,216,217,226,227,228,229,230,231,232,233, -1,224, -1, -1,109, /* 96 */ +- 121,129,130,131,132,133,134,135,136,137,145,146,147,148,149,150, /* 112 */ +- 151,152,153,162,163,164,165,166,167,168,169,192, 79,208,161, 7, /* 128 */ +- 32, 33, 34, 35, 36, 21, 6, 23, 40, 41, 42, 43, 44, 9, 10, 27, /* 144 */ +- 48, 49, 26, 51, 52, 53, 54, 8, 56, 57, 58, 59, 4, 20, 62,255, /* 160 */ +- -1, -1, 74, -1, -1, -1,106, -1, -1, -1, -1, -1, 95, -1, -1, -1, /* 176 */ +- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 192 */ +- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 208 */ +- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 224 */ +- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 240 */ +- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 256 */ +-}; +- +- +-static int iso_8859_1_to_ibm1047_table[] = { +- 0, 1, 2, 3, 55, 45, 46, 47, 22, 5, 37, 11, 12, 13, 14, 15, /* 16 */ +- 16, 17, 18, 19, 60, 61, 50, 38, 24, 25, 63, 39, 28, 29, 30, 31, /* 32 */ +- 64, 90,127,123, 91,108, 80,125, 77, 93, 92, 78,107, 96, 75, 97, /* 48 */ +- 240,241,242,243,244,245,246,247,248,249,122, 94, 76,126,110,111, /* 64 */ +- 124,193,194,195,196,197,198,199,200,201,209,210,211,212,213,214, /* 80 */ +- 215,216,217,226,227,228,229,230,231,232,233,173,224,189, 95,109, /* 96 */ +- 121,129,130,131,132,133,134,135,136,137,145,146,147,148,149,150, /* 112 */ +- 151,152,153,162,163,164,165,166,167,168,169,192, 79,208,161, 7, /* 128 */ +- 32, 33, 34, 35, 36, 21, 6, 23, 40, 41, 42, 43, 44, 9, 10, 27, /* 144 */ +- 48, 49, 26, 51, 52, 53, 54, 8, 56, 57, 58, 59, 4, 20, 62,255, /* 160 */ +- 65,170, 74,177,159,178,106,181,187,180,154,138,176,202,175,188, /* 176 */ +- 144,143,234,250,190,160,182,179,157,218,155,139,183,184,185,171, /* 192 */ +- 100,101, 98,102, 99,103,158,104,116,113,114,115,120,117,118,119, /* 208 */ +- 172,105,237,238,235,239,236,191,128,253,254,251,252,186,174, 89, /* 224 */ +- 68, 69, 66, 70, 67, 71,156, 72, 84, 81, 82, 83, 88, 85, 86, 87, /* 240 */ +- 140, 73,205,206,203,207,204,225,112,221,222,219,220,141,142,223 /* 256 */ +-}; +- +- +-static int ebcdic_us_to_ascii_table[] = { +- 0, 1, 2, 3, -1, 9, -1,127, -1, -1, -1, 11, 12, 13, 14, 15, /* 16 */ +- 16, 17, 18, 19, -1, -1, 8, -1, 24, 25, -1, -1, 28, 29, 30, 31, /* 32 */ +- -1, -1, -1, -1, -1, 10, 23, 27, -1, -1, -1, -1, -1, 5, 6, 7, /* 48 */ +- -1, -1, 22, -1, -1, -1, -1, 4, -1, -1, -1, -1, 20, 21, -1, 26, /* 64 */ +- 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 46, 60, 40, 43,124, /* 80 */ +- 38, -1, -1, -1, -1, -1, -1, -1, -1, -1, 33, 36, 42, 41, 59, -1, /* 96 */ +- 45, 47, -1, -1, -1, -1, -1, -1, -1, -1, -1, 44, 37, 95, 62, 63, /* 112 */ +- -1, -1, -1, -1, -1, -1, -1, -1, -1, 96, 58, 35, 64, 39, 61, 34, /* 128 */ +- -1, 97, 98, 99,100,101,102,103,104,105, -1, -1, -1, -1, -1, -1, /* 144 */ +- -1,106,107,108,109,110,111,112,113,114, -1, -1, -1, -1, -1, -1, /* 160 */ +- -1,126,115,116,117,118,119,120,121,122, -1, -1, -1, -1, -1, -1, /* 176 */ +- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 192 */ +- 123, 65, 66, 67, 68, 69, 70, 71, 72, 73, -1, -1, -1, -1, -1, -1, /* 208 */ +- 125, 74, 75, 76, 77, 78, 79, 80, 81, 82, -1, -1, -1, -1, -1, -1, /* 224 */ +- 92, -1, 83, 84, 85, 86, 87, 88, 89, 90, -1, -1, -1, -1, -1, -1, /* 240 */ +- 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, -1, -1, -1, -1, -1 /* 256 */ +-}; +- +- +-static int ebcdic_us_to_iso_8859_1_table[] = { +- 0, 1, 2, 3,156, 9,134,127,151,141,142, 11, 12, 13, 14, 15, /* 16 */ +- 16, 17, 18, 19,157,133, 8,135, 24, 25,146,143, 28, 29, 30, 31, /* 32 */ +- 128,129,130,131,132, 10, 23, 27,136,137,138,139,140, 5, 6, 7, /* 48 */ +- 144,145, 22,147,148,149,150, 4,152,153,154,155, 20, 21,158, 26, /* 64 */ +- 32, -1, -1, -1, -1, -1, -1, -1, -1, -1,162, 46, 60, 40, 43,124, /* 80 */ +- 38, -1, -1, -1, -1, -1, -1, -1, -1, -1, 33, 36, 42, 41, 59,172, /* 96 */ +- 45, 47, -1, -1, -1, -1, -1, -1, -1, -1,166, 44, 37, 95, 62, 63, /* 112 */ +- -1, -1, -1, -1, -1, -1, -1, -1, -1, 96, 58, 35, 64, 39, 61, 34, /* 128 */ +- -1, 97, 98, 99,100,101,102,103,104,105, -1, -1, -1, -1, -1, -1, /* 144 */ +- -1,106,107,108,109,110,111,112,113,114, -1, -1, -1, -1, -1, -1, /* 160 */ +- -1,126,115,116,117,118,119,120,121,122, -1, -1, -1, -1, -1, -1, /* 176 */ +- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 192 */ +- 123, 65, 66, 67, 68, 69, 70, 71, 72, 73, -1, -1, -1, -1, -1, -1, /* 208 */ +- 125, 74, 75, 76, 77, 78, 79, 80, 81, 82, -1, -1, -1, -1, -1, -1, /* 224 */ +- 92, -1, 83, 84, 85, 86, 87, 88, 89, 90, -1, -1, -1, -1, -1, -1, /* 240 */ +- 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, -1, -1, -1, -1,159 /* 256 */ +-}; +- +- +-static int ebcdic_us_to_ibm1047_table[] = { +- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 16 */ +- 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, /* 32 */ +- 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, /* 48 */ +- 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, /* 64 */ +- 64, -1, -1, -1, -1, -1, -1, -1, -1, -1, 74, 75, 76, 77, 78, 79, /* 80 */ +- 80, -1, -1, -1, -1, -1, -1, -1, -1, -1, 90, 91, 92, 93, 94,176, /* 96 */ +- 96, 97, -1, -1, -1, -1, -1, -1, -1, -1,106,107,108,109,110,111, /* 112 */ +- -1, -1, -1, -1, -1, -1, -1, -1, -1,121,122,123,124,125,126,127, /* 128 */ +- -1,129,130,131,132,133,134,135,136,137, -1, -1, -1, -1, -1, -1, /* 144 */ +- -1,145,146,147,148,149,150,151,152,153, -1, -1, -1, -1, -1, -1, /* 160 */ +- -1,161,162,163,164,165,166,167,168,169, -1, -1, -1, -1, -1, -1, /* 176 */ +- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 192 */ +- 192,193,194,195,196,197,198,199,200,201, -1, -1, -1, -1, -1, -1, /* 208 */ +- 208,209,210,211,212,213,214,215,216,217, -1, -1, -1, -1, -1, -1, /* 224 */ +- 224, -1,226,227,228,229,230,231,232,233, -1, -1, -1, -1, -1, -1, /* 240 */ +- 240,241,242,243,244,245,246,247,248,249, -1, -1, -1, -1, -1,255 /* 256 */ +-}; +- +- +-static int ibm1047_to_ascii_table[] = { +- 0, 1, 2, 3, -1, 9, -1,127, -1, -1, -1, 11, 12, 13, 14, 15, /* 16 */ +- 16, 17, 18, 19, -1, -1, 8, -1, 24, 25, -1, -1, 28, 29, 30, 31, /* 32 */ +- -1, -1, -1, -1, -1, 10, 23, 27, -1, -1, -1, -1, -1, 5, 6, 7, /* 48 */ +- -1, -1, 22, -1, -1, -1, -1, 4, -1, -1, -1, -1, 20, 21, -1, 26, /* 64 */ +- 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 46, 60, 40, 43,124, /* 80 */ +- 38, -1, -1, -1, -1, -1, -1, -1, -1, -1, 33, 36, 42, 41, 59, 94, /* 96 */ +- 45, 47, -1, -1, -1, -1, -1, -1, -1, -1, -1, 44, 37, 95, 62, 63, /* 112 */ +- -1, -1, -1, -1, -1, -1, -1, -1, -1, 96, 58, 35, 64, 39, 61, 34, /* 128 */ +- -1, 97, 98, 99,100,101,102,103,104,105, -1, -1, -1, -1, -1, -1, /* 144 */ +- -1,106,107,108,109,110,111,112,113,114, -1, -1, -1, -1, -1, -1, /* 160 */ +- -1,126,115,116,117,118,119,120,121,122, -1, -1, -1, 91, -1, -1, /* 176 */ +- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 93, -1, -1, /* 192 */ +- 123, 65, 66, 67, 68, 69, 70, 71, 72, 73, -1, -1, -1, -1, -1, -1, /* 208 */ +- 125, 74, 75, 76, 77, 78, 79, 80, 81, 82, -1, -1, -1, -1, -1, -1, /* 224 */ +- 92, -1, 83, 84, 85, 86, 87, 88, 89, 90, -1, -1, -1, -1, -1, -1, /* 240 */ +- 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, -1, -1, -1, -1, -1 /* 256 */ +-}; +- +- +-static int ibm1047_to_iso_8859_1_table[] = { +- 0, 1, 2, 3,156, 9,134,127,151,141,142, 11, 12, 13, 14, 15, /* 16 */ +- 16, 17, 18, 19,157,133, 8,135, 24, 25,146,143, 28, 29, 30, 31, /* 32 */ +- 128,129,130,131,132, 10, 23, 27,136,137,138,139,140, 5, 6, 7, /* 48 */ +- 144,145, 22,147,148,149,150, 4,152,153,154,155, 20, 21,158, 26, /* 64 */ +- 32,160,226,228,224,225,227,229,231,241,162, 46, 60, 40, 43,124, /* 80 */ +- 38,233,234,235,232,237,238,239,236,223, 33, 36, 42, 41, 59, 94, /* 96 */ +- 45, 47,194,196,192,193,195,197,199,209,166, 44, 37, 95, 62, 63, /* 112 */ +- 248,201,202,203,200,205,206,207,204, 96, 58, 35, 64, 39, 61, 34, /* 128 */ +- 216, 97, 98, 99,100,101,102,103,104,105,171,187,240,253,254,177, /* 144 */ +- 176,106,107,108,109,110,111,112,113,114,170,186,230,184,198,164, /* 160 */ +- 181,126,115,116,117,118,119,120,121,122,161,191,208, 91,222,174, /* 176 */ +- 172,163,165,183,169,167,182,188,189,190,221,168,175, 93,180,215, /* 192 */ +- 123, 65, 66, 67, 68, 69, 70, 71, 72, 73,173,244,246,242,243,245, /* 208 */ +- 125, 74, 75, 76, 77, 78, 79, 80, 81, 82,185,251,252,249,250,255, /* 224 */ +- 92,247, 83, 84, 85, 86, 87, 88, 89, 90,178,212,214,210,211,213, /* 240 */ +- 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,179,219,220,217,218,159 /* 256 */ +-}; +- +- +-static int ibm1047_to_ebcdic_us_table[] = { +- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 16 */ +- 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, /* 32 */ +- 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, /* 48 */ +- 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, /* 64 */ +- 64, -1, -1, -1, -1, -1, -1, -1, -1, -1, 74, 75, 76, 77, 78, 79, /* 80 */ +- 80, -1, -1, -1, -1, -1, -1, -1, -1, -1, 90, 91, 92, 93, 94, -1, /* 96 */ +- 96, 97, -1, -1, -1, -1, -1, -1, -1, -1,106,107,108,109,110,111, /* 112 */ +- -1, -1, -1, -1, -1, -1, -1, -1, -1,121,122,123,124,125,126,127, /* 128 */ +- -1,129,130,131,132,133,134,135,136,137, -1, -1, -1, -1, -1, -1, /* 144 */ +- -1,145,146,147,148,149,150,151,152,153, -1, -1, -1, -1, -1, -1, /* 160 */ +- -1,161,162,163,164,165,166,167,168,169, -1, -1, -1, -1, -1, -1, /* 176 */ +- 95, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 192 */ +- 192,193,194,195,196,197,198,199,200,201, -1, -1, -1, -1, -1, -1, /* 208 */ +- 208,209,210,211,212,213,214,215,216,217, -1, -1, -1, -1, -1, -1, /* 224 */ +- 224, -1,226,227,228,229,230,231,232,233, -1, -1, -1, -1, -1, -1, /* 240 */ +- 240,241,242,243,244,245,246,247,248,249, -1, -1, -1, -1, -1,255 /* 256 */ +-}; ++ desc = iconv_open (to, from); ++ if (desc == (iconv_t) -1) ++ perror_with_name ("Converting character sets"); ++ cleanups = make_cleanup (cleanup_iconv, &desc); + ++ inleft = num_bytes; ++ inp = (char *) bytes; + +-static int +-table_convert_char (void *baton, int from, int *to) +-{ +- int *table = (int *) baton; ++ space_request = num_bytes; + +- if (0 <= from && from <= 255 +- && table[from] != -1) ++ while (inleft > 0) + { +- *to = table[from]; +- return 1; ++ char *outp; ++ size_t outleft, r; ++ int old_size; ++ ++ old_size = obstack_object_size (output); ++ obstack_blank (output, space_request); ++ ++ outp = obstack_base (output) + old_size; ++ outleft = space_request; ++ ++ r = iconv (desc, &inp, &inleft, &outp, &outleft); ++ ++ /* Now make sure that the object on the obstack only includes ++ bytes we have converted. */ ++ obstack_blank (output, - (int) outleft); ++ ++ if (r == (size_t) -1) ++ { ++ switch (errno) ++ { ++ case EILSEQ: ++ { ++ int i; ++ ++ /* Invalid input sequence. */ ++ if (translit == translit_none) ++ error (_("Could not convert character to `%s' character set"), ++ to); ++ ++ /* We emit escape sequence for the bytes, skip them, ++ and try again. */ ++ for (i = 0; i < width; ++i) ++ { ++ char octal[5]; ++ ++ sprintf (octal, "\\%.3o", *inp & 0xff); ++ obstack_grow_str (output, octal); ++ ++ ++inp; ++ --inleft; ++ } ++ } ++ break; ++ ++ case E2BIG: ++ /* We ran out of space in the output buffer. Make it ++ bigger next time around. */ ++ space_request *= 2; ++ break; ++ ++ case EINVAL: ++ /* Incomplete input sequence. FIXME: ought to report this ++ to the caller somehow. */ ++ inleft = 0; ++ break; ++ ++ default: ++ perror_with_name ("Internal error while converting character sets"); ++ } ++ } + } +- else +- return 0; +-} +- + +-static struct translation * +-table_translation (const char *from, const char *to, int *table, +- const char *(*c_target_char_has_backslash_escape) +- (void *baton, int target_char), +- void *c_target_char_has_backslash_escape_baton, +- int (*c_parse_backslash) (void *baton, +- int host_char, +- int *target_char), +- void *c_parse_backslash_baton) +-{ +- struct translation *t = xmalloc (sizeof (*t)); +- +- memset (t, 0, sizeof (*t)); +- t->from = from; +- t->to = to; +- t->c_target_char_has_backslash_escape = c_target_char_has_backslash_escape; +- t->c_target_char_has_backslash_escape_baton +- = c_target_char_has_backslash_escape_baton; +- t->c_parse_backslash = c_parse_backslash; +- t->c_parse_backslash_baton = c_parse_backslash_baton; +- t->convert_char = table_convert_char; +- t->convert_char_baton = (void *) table; +- +- return t; ++ do_cleanups (cleanups); + } + +- +-static struct translation * +-simple_table_translation (const char *from, const char *to, int *table) +-{ +- return table_translation (from, to, table, 0, 0, 0, 0); +-} +- +- + +-/* Setting and retrieving the host and target charsets. */ +- +- +-/* The current host and target character sets. */ +-static struct charset *current_host_charset, *current_target_charset; +- +-/* The current functions and batons we should use for the functions in +- charset.h. */ +- +-static const char *(*c_target_char_has_backslash_escape_func) +- (void *baton, int target_char); +-static void *c_target_char_has_backslash_escape_baton; +- +-static int (*c_parse_backslash_func) (void *baton, +- int host_char, +- int *target_char); +-static void *c_parse_backslash_baton; +- +-static int (*host_char_to_target_func) (void *baton, +- int host_char, +- int *target_char); +-static void *host_char_to_target_baton; +- +-static int (*target_char_to_host_func) (void *baton, +- int target_char, +- int *host_char); +-static void *target_char_to_host_baton; + +- +-/* Cached iconv conversions, that might be useful to fallback +- routines. */ +-static struct cached_iconv cached_iconv_host_to_target; +-static struct cached_iconv cached_iconv_target_to_host; +- +- +-/* Charset structures manipulation functions. */ +- +-static struct charset * +-lookup_charset_or_error (const char *name) ++/* An iterator that returns host wchar_t's from a target string. */ ++struct wchar_iterator + { +- struct charset *cs = lookup_charset (name); ++ /* The underlying iconv descriptor. */ ++ iconv_t desc; + +- if (! cs) +- error (_("GDB doesn't know of any character set named `%s'."), name); ++ /* The input string. This is updated as convert characters. */ ++ char *input; ++ /* The number of bytes remaining in the input. */ ++ size_t bytes; + +- return cs; +-} ++ /* The width of an input character. */ ++ size_t width; + +-static void +-check_valid_host_charset (struct charset *cs) +-{ +- if (! cs->valid_host_charset) +- error (_("GDB can't use `%s' as its host character set."), cs->name); +-} ++ /* The output buffer and its size. */ ++ wchar_t *out; ++ size_t out_size; ++}; + +-/* Set the host and target character sets to HOST and TARGET. */ +-static void +-set_host_and_target_charsets (struct charset *host, struct charset *target) ++/* Create a new iterator. */ ++struct wchar_iterator * ++make_wchar_iterator (const gdb_byte *input, size_t bytes, const char *charset, ++ size_t width) + { +- struct translation *h2t, *t2h; +- +- /* If they're not both initialized yet, then just do nothing for +- now. As soon as we're done running our initialize function, +- everything will be initialized. */ +- if (! host || ! target) +- { +- current_host_charset = host; +- current_target_charset = target; +- return; +- } +- +- h2t = lookup_translation (host->name, target->name); +- t2h = lookup_translation (target->name, host->name); +- +- /* If the translations don't provide conversion functions, make sure +- iconv can back them up. Do this *before* modifying any state. */ +- if (host != target) +- { +- if (! h2t || ! h2t->convert_char) +- { +- if (check_iconv_cache (&cached_iconv_host_to_target, host, target) +- < 0) +- error (_("GDB can't convert from the `%s' character set to `%s'."), +- host->name, target->name); +- } +- if (! t2h || ! t2h->convert_char) +- { +- if (check_iconv_cache (&cached_iconv_target_to_host, target, host) +- < 0) +- error (_("GDB can't convert from the `%s' character set to `%s'."), +- target->name, host->name); +- } +- } +- +- if (t2h && t2h->c_target_char_has_backslash_escape) +- { +- c_target_char_has_backslash_escape_func +- = t2h->c_target_char_has_backslash_escape; +- c_target_char_has_backslash_escape_baton +- = t2h->c_target_char_has_backslash_escape_baton; +- } +- else +- c_target_char_has_backslash_escape_func +- = default_c_target_char_has_backslash_escape; +- +- if (h2t && h2t->c_parse_backslash) +- { +- c_parse_backslash_func = h2t->c_parse_backslash; +- c_parse_backslash_baton = h2t->c_parse_backslash_baton; +- } +- else +- c_parse_backslash_func = default_c_parse_backslash; +- +- if (h2t && h2t->convert_char) +- { +- host_char_to_target_func = h2t->convert_char; +- host_char_to_target_baton = h2t->convert_char_baton; +- } +- else if (host == target) +- host_char_to_target_func = identity_either_char_to_other; +- else +- { +- host_char_to_target_func = iconv_convert; +- host_char_to_target_baton = &cached_iconv_host_to_target; +- } ++ struct wchar_iterator *result; ++ iconv_t desc; + +- if (t2h && t2h->convert_char) +- { +- target_char_to_host_func = t2h->convert_char; +- target_char_to_host_baton = t2h->convert_char_baton; +- } +- else if (host == target) +- target_char_to_host_func = identity_either_char_to_other; +- else +- { +- target_char_to_host_func = iconv_convert; +- target_char_to_host_baton = &cached_iconv_target_to_host; +- } ++ desc = iconv_open ("wchar_t", charset); ++ if (desc == (iconv_t) -1) ++ perror_with_name ("Converting character sets"); + +- current_host_charset = host; +- current_target_charset = target; +-} +- +-/* Do the real work of setting the host charset. */ +-static void +-set_host_charset (const char *charset) +-{ +- struct charset *cs = lookup_charset_or_error (charset); +- check_valid_host_charset (cs); +- set_host_and_target_charsets (cs, current_target_charset); +-} ++ result = XNEW (struct wchar_iterator); ++ result->desc = desc; ++ result->input = (char *) input; ++ result->bytes = bytes; ++ result->width = width; + +-/* Do the real work of setting the target charset. */ +-static void +-set_target_charset (const char *charset) +-{ +- struct charset *cs = lookup_charset_or_error (charset); ++ result->out = XNEW (wchar_t); ++ result->out_size = 1; + +- set_host_and_target_charsets (current_host_charset, cs); ++ return result; + } + +- +-/* 'Set charset', 'set host-charset', 'set target-charset', 'show +- charset' sfunc's. */ +- +-/* This is the sfunc for the 'set charset' command. */ + static void +-set_charset_sfunc (char *charset, int from_tty, struct cmd_list_element *c) ++do_cleanup_iterator (void *p) + { +- struct charset *cs = lookup_charset_or_error (host_charset_name); +- check_valid_host_charset (cs); +- /* CAREFUL: set the target charset here as well. */ +- target_charset_name = host_charset_name; +- set_host_and_target_charsets (cs, cs); +-} ++ struct wchar_iterator *iter = p; + +-/* 'set host-charset' command sfunc. We need a wrapper here because +- the function needs to have a specific signature. */ +-static void +-set_host_charset_sfunc (char *charset, int from_tty, +- struct cmd_list_element *c) +-{ +- set_host_charset (host_charset_name); ++ iconv_close (iter->desc); ++ xfree (iter->out); ++ xfree (iter); + } + +-/* Wrapper for the 'set target-charset' command. */ +-static void +-set_target_charset_sfunc (char *charset, int from_tty, +- struct cmd_list_element *c) ++struct cleanup * ++make_cleanup_wchar_iterator (struct wchar_iterator *iter) + { +- set_target_charset (target_charset_name); ++ return make_cleanup (do_cleanup_iterator, iter); + } + +-/* sfunc for the 'show charset' command. */ +-static void +-show_charset (struct ui_file *file, int from_tty, struct cmd_list_element *c, +- const char *name) +-{ +- if (current_host_charset == current_target_charset) +- fprintf_filtered (file, +- _("The current host and target character set is `%s'.\n"), +- host_charset ()); +- else ++int ++wchar_iterate (struct wchar_iterator *iter, ++ enum wchar_iterate_result *out_result, ++ wchar_t **out_chars, ++ const gdb_byte **ptr, ++ size_t *len) ++{ ++ size_t out_request; ++ ++ /* Try to convert some characters. At first we try to convert just ++ a single character. The reason for this is that iconv does not ++ necessarily update its outgoing arguments when it encounters an ++ invalid input sequence -- but we want to reliably report this to ++ our caller so it can emit an escape sequence. */ ++ out_request = 1; ++ while (iter->bytes > 0) + { +- fprintf_filtered (file, _("The current host character set is `%s'.\n"), +- host_charset ()); +- fprintf_filtered (file, _("The current target character set is `%s'.\n"), +- target_charset ()); ++ char *outptr = (char *) &iter->out[0]; ++ char *orig_inptr = iter->input; ++ size_t orig_in = iter->bytes; ++ size_t out_avail = out_request * sizeof (wchar_t); ++ size_t num; ++ wchar_t result; ++ ++ size_t r = iconv (iter->desc, (char **) &iter->input, &iter->bytes, ++ &outptr, &out_avail); ++ if (r == (size_t) -1) ++ { ++ switch (errno) ++ { ++ case EILSEQ: ++ /* Invalid input sequence. Skip it, and let the caller ++ know about it. */ ++ *out_result = wchar_iterate_invalid; ++ *ptr = iter->input; ++ *len = iter->width; ++ iter->input += iter->width; ++ iter->bytes -= iter->width; ++ return 0; ++ ++ case E2BIG: ++ /* We ran out of space. We still might have converted a ++ character; if so, return it. Otherwise, grow the ++ buffer and try again. */ ++ if (out_avail < out_request * sizeof (wchar_t)) ++ break; ++ ++ ++out_request; ++ if (out_request > iter->out_size) ++ { ++ iter->out_size = out_request; ++ iter->out = xrealloc (iter->out, ++ out_request * sizeof (wchar_t)); ++ } ++ continue; ++ ++ case EINVAL: ++ /* Incomplete input sequence. Let the caller know, and ++ arrange for future calls to see EOF. */ ++ *out_result = wchar_iterate_incomplete; ++ *ptr = iter->input; ++ *len = iter->bytes; ++ iter->bytes = 0; ++ return 0; ++ ++ default: ++ perror_with_name ("Internal error while converting character sets"); ++ } ++ } ++ ++ /* We converted something. */ ++ num = out_request - out_avail / sizeof (wchar_t); ++ *out_result = wchar_iterate_ok; ++ *out_chars = iter->out; ++ *ptr = orig_inptr; ++ *len = orig_in - iter->bytes; ++ return num; + } ++ ++ /* Really done. */ ++ *out_result = wchar_iterate_eof; ++ return -1; + } + + +-/* Accessor functions. */ ++/* The charset.c module initialization function. */ + +-const char * +-host_charset (void) +-{ +- return current_host_charset->name; +-} ++extern initialize_file_ftype _initialize_charset; /* -Wmissing-prototype */ + +-const char * +-target_charset (void) +-{ +- return current_target_charset->name; +-} ++typedef char *char_ptr; ++DEF_VEC_P (char_ptr); + ++static VEC (char_ptr) *charsets; + +- +-/* Public character management functions. */ ++#ifdef HAVE_ICONVLIST + ++/* A helper function that adds some character sets to the vector of ++ all character sets. This is a callback function for iconvlist. */ + +-const char * +-c_target_char_has_backslash_escape (int target_char) ++static int ++add_one (unsigned int count, const char *const *names, void *data) + { +- return ((*c_target_char_has_backslash_escape_func) +- (c_target_char_has_backslash_escape_baton, target_char)); +-} ++ unsigned int i; + ++ for (i = 0; i < count; ++i) ++ VEC_safe_push (char_ptr, charsets, xstrdup (names[i])); + +-int +-c_parse_backslash (int host_char, int *target_char) +-{ +- return (*c_parse_backslash_func) (c_parse_backslash_baton, +- host_char, target_char); ++ return 0; + } + +- +-int +-host_char_print_literally (int host_char) ++static void ++find_charset_names (void) + { +- return ((*current_host_charset->host_char_print_literally) +- (current_host_charset->host_char_print_literally_baton, +- host_char)); ++ iconvlist (add_one, NULL); ++ VEC_safe_push (char_ptr, charsets, NULL); + } + ++#else + +-int +-target_char_to_control_char (int target_char, int *target_ctrl_char) ++static void ++find_charset_names (void) + { +- return ((*current_target_charset->target_char_to_control_char) +- (current_target_charset->target_char_to_control_char_baton, +- target_char, target_ctrl_char)); +-} ++ FILE *in; + ++ in = popen ("iconv -l", "r"); ++ /* It is ok to ignore errors; we'll fall back on a default. */ ++ if (!in) ++ return; + +-int +-host_char_to_target (int host_char, int *target_char) +-{ +- return ((*host_char_to_target_func) +- (host_char_to_target_baton, host_char, target_char)); +-} ++ /* POSIX says that iconv -l uses an unspecified format. We parse ++ the glibc format; feel free to add others as needed. */ ++ while (!feof (in)) ++ { ++ /* The size of buf is chosen arbitrarily. A character set name ++ longer than this would not be very nice. */ ++ char buf[80]; ++ int len; ++ char *r = fgets (buf, sizeof (buf), in); ++ if (!r) ++ break; ++ len = strlen (r); ++ if (len <= 3) ++ continue; ++ if (buf[len - 2] == '/' && buf[len - 3] == '/') ++ buf[len - 3] = '\0'; ++ VEC_safe_push (char_ptr, charsets, xstrdup (buf)); ++ } + ++ pclose (in); + +-int +-target_char_to_host (int target_char, int *host_char) +-{ +- return ((*target_char_to_host_func) +- (target_char_to_host_baton, target_char, host_char)); ++ VEC_safe_push (char_ptr, charsets, NULL); + } + +- +- +-/* The charset.c module initialization function. */ +- +-extern initialize_file_ftype _initialize_charset; /* -Wmissing-prototype */ ++#endif /* HAVE_ICONVLIST */ + + void + _initialize_charset (void) + { + struct cmd_list_element *new_cmd; + +- /* Register all the character set GDB knows about. +- +- You should use the same names that iconv does, where possible, to +- take advantage of the iconv-based default behaviors. +- +- CAUTION: if you register a character set, you must also register +- as many translations as are necessary to make that character set +- interoperate correctly with all the other character sets. We do +- provide default behaviors when no translation is available, or +- when a translation's function pointer for a particular operation +- is zero. Hopefully, these defaults will be correct often enough +- that we won't need to provide too many translations. */ +- register_charset (simple_charset ("ASCII", 1, +- ascii_print_literally, 0, +- ascii_to_control, 0)); +- register_charset (iso_8859_family_charset ("ISO-8859-1")); +- register_charset (ebcdic_family_charset ("EBCDIC-US")); +- register_charset (ebcdic_family_charset ("IBM1047")); +- register_iconv_charsets (); +- +- { +- struct { char *from; char *to; int *table; } tlist[] = { +- { "ASCII", "ISO-8859-1", ascii_to_iso_8859_1_table }, +- { "ASCII", "EBCDIC-US", ascii_to_ebcdic_us_table }, +- { "ASCII", "IBM1047", ascii_to_ibm1047_table }, +- { "ISO-8859-1", "ASCII", iso_8859_1_to_ascii_table }, +- { "ISO-8859-1", "EBCDIC-US", iso_8859_1_to_ebcdic_us_table }, +- { "ISO-8859-1", "IBM1047", iso_8859_1_to_ibm1047_table }, +- { "EBCDIC-US", "ASCII", ebcdic_us_to_ascii_table }, +- { "EBCDIC-US", "ISO-8859-1", ebcdic_us_to_iso_8859_1_table }, +- { "EBCDIC-US", "IBM1047", ebcdic_us_to_ibm1047_table }, +- { "IBM1047", "ASCII", ibm1047_to_ascii_table }, +- { "IBM1047", "ISO-8859-1", ibm1047_to_iso_8859_1_table }, +- { "IBM1047", "EBCDIC-US", ibm1047_to_ebcdic_us_table } +- }; +- +- int i; +- +- for (i = 0; i < (sizeof (tlist) / sizeof (tlist[0])); i++) +- register_translation (simple_table_translation (tlist[i].from, +- tlist[i].to, +- tlist[i].table)); +- } +- +- set_host_charset (host_charset_name); +- set_target_charset (target_charset_name); ++ /* The first element is always "auto"; then we skip it for the ++ commands where it is not allowed. */ ++ VEC_safe_push (char_ptr, charsets, "auto"); ++ find_charset_names (); ++ ++ if (VEC_length (char_ptr, charsets) > 1) ++ charset_enum = default_charset_names; ++ else ++ charset_enum = (const char **) VEC_address (char_ptr, charsets); ++ ++#ifdef HAVE_LANGINFO_CODESET ++ auto_host_charset_name = nl_langinfo (CODESET); ++ target_charset_name = auto_host_charset_name; ++ ++ set_be_le_names (); ++#endif + + add_setshow_enum_cmd ("charset", class_support, +- host_charset_enum, &host_charset_name, _("\ ++ &charset_enum[1], &host_charset_name, _("\ + Set the host and target character sets."), _("\ + Show the host and target character sets."), _("\ + The `host character set' is the one used by the system GDB is running on.\n\ +@@ -1249,7 +650,7 @@ To see a list of the character sets GDB supports, type `set charset '."), + &setlist, &showlist); + + add_setshow_enum_cmd ("host-charset", class_support, +- host_charset_enum, &host_charset_name, _("\ ++ charset_enum, &host_charset_name, _("\ + Set the host character set."), _("\ + Show the host character set."), _("\ + The `host character set' is the one used by the system GDB is running on.\n\ +@@ -1261,7 +662,7 @@ To see a list of the character sets GDB supports, type `set host-charset '. + &setlist, &showlist); + + add_setshow_enum_cmd ("target-charset", class_support, +- target_charset_enum, &target_charset_name, _("\ ++ &charset_enum[1], &target_charset_name, _("\ + Set the target character set."), _("\ + Show the target character set."), _("\ + The `target character set' is the one used by the program being debugged.\n\ +@@ -1271,4 +672,19 @@ To see a list of the character sets GDB supports, type `set target-charset' + set_target_charset_sfunc, + show_target_charset_name, + &setlist, &showlist); ++ ++ add_setshow_enum_cmd ("target-wide-charset", class_support, ++ &charset_enum[1], &target_wide_charset_name, ++ _("\ ++Set the target wide character set."), _("\ ++Show the target wide character set."), _("\ ++The `target wide character set' is the one used by the program being debugged.\n\ ++In particular it is the encoding used by `wchar_t'.\n\ ++GDB translates characters and strings between the host and target\n\ ++character sets as needed.\n\ ++To see a list of the character sets GDB supports, type\n\ ++`set target-wide-charset'"), ++ set_target_wide_charset_sfunc, ++ show_target_wide_charset_name, ++ &setlist, &showlist); + } +diff --git a/gdb/charset.h b/gdb/charset.h +index 21780b6..2455355 100644 +--- a/gdb/charset.h ++++ b/gdb/charset.h +@@ -19,6 +19,7 @@ + #ifndef CHARSET_H + #define CHARSET_H + ++#include + + /* If the target program uses a different character set than the host, + GDB has some support for translating between the two; GDB converts +@@ -26,82 +27,123 @@ + them, and converts characters and strings appearing in expressions + entered by the user to the target character set. + +- At the moment, GDB only supports single-byte, stateless character +- sets. This includes the ISO-8859 family (ASCII extended with +- accented characters, and (I think) Cyrillic, for European +- languages), and the EBCDIC family (used on IBM's mainframes). +- Unfortunately, it excludes many Asian scripts, the fixed- and +- variable-width Unicode encodings, and other desireable things. +- Patches are welcome! (For example, it would be nice if the Java +- string support could simply get absorbed into some more general +- multi-byte encoding support.) +- +- Furthermore, GDB's code pretty much assumes that the host character +- set is some superset of ASCII; there are plenty if ('0' + n) +- expressions and the like. +- +- When the `iconv' library routine supports a character set meeting +- the requirements above, it's easy to plug an entry into GDB's table +- that uses iconv to handle the details. */ ++ GDB's code pretty much assumes that the host character set is some ++ superset of ASCII; there are plenty if ('0' + n) expressions and ++ the like. */ + + /* Return the name of the current host/target character set. The + result is owned by the charset module; the caller should not free + it. */ + const char *host_charset (void); + const char *target_charset (void); +- +-/* In general, the set of C backslash escapes (\n, \f) is specific to +- the character set. Not all character sets will have form feed +- characters, for example. +- +- The following functions allow GDB to parse and print control +- characters in a character-set-independent way. They are both +- language-specific (to C and C++) and character-set-specific. +- Putting them here is a compromise. */ +- +- +-/* If the target character TARGET_CHAR have a backslash escape in the +- C language (i.e., a character like 'n' or 't'), return the host +- character string that should follow the backslash. Otherwise, +- return zero. +- +- When this function returns non-zero, the string it returns is +- statically allocated; the caller is not responsible for freeing it. */ +-const char *c_target_char_has_backslash_escape (int target_char); +- +- +-/* If the host character HOST_CHAR is a valid backslash escape in the +- C language for the target character set, return non-zero, and set +- *TARGET_CHAR to the target character the backslash escape represents. +- Otherwise, return zero. */ +-int c_parse_backslash (int host_char, int *target_char); +- +- +-/* Return non-zero if the host character HOST_CHAR can be printed +- literally --- that is, if it can be readably printed as itself in a +- character or string constant. Return zero if it should be printed +- using some kind of numeric escape, like '\031' in C, '^(25)' in +- Chill, or #25 in Pascal. */ +-int host_char_print_literally (int host_char); +- +- +-/* If the host character HOST_CHAR has an equivalent in the target +- character set, set *TARGET_CHAR to that equivalent, and return +- non-zero. Otherwise, return zero. */ +-int host_char_to_target (int host_char, int *target_char); +- +- +-/* If the target character TARGET_CHAR has an equivalent in the host +- character set, set *HOST_CHAR to that equivalent, and return +- non-zero. Otherwise, return zero. */ +-int target_char_to_host (int target_char, int *host_char); +- +- +-/* If the target character TARGET_CHAR has a corresponding control +- character (also in the target character set), set *TARGET_CTRL_CHAR +- to the control character, and return non-zero. Otherwise, return +- zero. */ +-int target_char_to_control_char (int target_char, int *target_ctrl_char); +- ++const char *target_wide_charset (void); ++ ++/* These values are used to specify the type of transliteration done ++ by convert_between_encodings. */ ++enum transliterations ++ { ++ /* Error on failure to convert. */ ++ translit_none, ++ /* Transliterate to host char. */ ++ translit_char ++ }; ++ ++/* Convert between two encodings. ++ ++ FROM is the name of the source encoding. ++ TO is the name of the target encoding. ++ BYTES holds the bytes to convert; this is assumed to be characters ++ in the target encoding. ++ NUM_BYTES is the number of bytes. ++ WIDTH is the width of a character from the FROM charset, in bytes. ++ For a variable width encoding, WIDTH should be the size of a "base ++ character". ++ OUTPUT is an obstack where the converted data is written. The ++ caller is responsible for initializing the obstack, and for ++ destroying the obstack should an error occur. ++ TRANSLIT specifies how invalid conversions should be handled. */ ++void convert_between_encodings (const char *from, const char *to, ++ const gdb_byte *bytes, unsigned int num_bytes, ++ int width, struct obstack *output, ++ enum transliterations translit); ++ ++ ++/* These values are used by wchar_iterate to report errors. */ ++enum wchar_iterate_result ++ { ++ /* Ordinary return. */ ++ wchar_iterate_ok, ++ /* Invalid input sequence. */ ++ wchar_iterate_invalid, ++ /* Incomplete input sequence at the end of the input. */ ++ wchar_iterate_incomplete, ++ /* EOF. */ ++ wchar_iterate_eof ++ }; ++ ++/* Declaration of the opaque wchar iterator type. */ ++struct wchar_iterator; ++ ++/* Create a new character iterator which returns wchar_t's. INPUT is ++ the input buffer. BYTES is the number of bytes in the input ++ buffer. CHARSET is the name of the character set in which INPUT is ++ encoded. WIDTH is the number of bytes in a base character of ++ CHARSET. ++ ++ This function either returns a new character set iterator, or calls ++ error. The result can be freed using a cleanup; see ++ make_cleanup_wchar_iterator. */ ++struct wchar_iterator *make_wchar_iterator (const gdb_byte *input, size_t bytes, ++ const char *charset, ++ size_t width); ++ ++/* Return a new cleanup suitable for destroying the wchar iterator ++ ITER. */ ++struct cleanup *make_cleanup_wchar_iterator (struct wchar_iterator *iter); ++ ++/* Perform a single iteration of a wchar_t iterator. ++ ++ Returns the number of characters converted. A negative result ++ means that EOF has been reached. A positive result indicates the ++ number of valid wchar_ts in the result; *OUT_CHARS is updated to ++ point to the first valid character. ++ ++ In all cases aside from EOF, *PTR is set to point to the first ++ converted target byte. *LEN is set to the number of bytes ++ converted. ++ ++ A zero result means one of several unusual results. *OUT_RESULT is ++ set to indicate the type of un-ordinary return. ++ ++ wchar_iterate_invalid means that an invalid input character was ++ seen. The iterator is advanced by WIDTH (the argument to ++ make_wchar_iterator) bytes. ++ ++ wchar_iterate_incomplete means that an incomplete character was ++ seen at the end of the input sequence. ++ ++ wchar_iterate_eof means that all bytes were successfully ++ converted. The other output arguments are not set. */ ++int wchar_iterate (struct wchar_iterator *iter, ++ enum wchar_iterate_result *out_result, ++ wchar_t **out_chars, ++ const gdb_byte **ptr, size_t *len); ++ ++ ++ ++/* GDB needs to know a few details of its execution character set. ++ This knowledge is isolated here and in charset.c. */ ++ ++/* The escape character. */ ++#define HOST_ESCAPE_CHAR 27 ++ ++/* Convert a letter, like 'c', to its corresponding control ++ character. */ ++char host_letter_to_control_character (char c); ++ ++/* Convert a hex digit character to its numeric value. E.g., 'f' is ++ converted to 15. This function assumes that C is a valid hex ++ digit. Both upper- and lower-case letters are recognized. */ ++int host_hex_value (char c); + + #endif /* CHARSET_H */ +diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c +index 4d9c4f3..5fbe398 100644 +--- a/gdb/cli/cli-cmds.c ++++ b/gdb/cli/cli-cmds.c +@@ -45,6 +45,8 @@ + #include "cli/cli-setshow.h" + #include "cli/cli-cmds.h" + ++#include "python/python.h" ++ + #ifdef TUI + #include "tui/tui.h" /* For tui_active et.al. */ + #endif +@@ -178,6 +180,7 @@ struct cmd_list_element *showchecklist; + + /* Command tracing state. */ + ++static int source_python = 0; + int source_verbose = 0; + int trace_commands = 0; + +@@ -439,6 +442,7 @@ source_script (char *file, int from_tty) + struct cleanup *old_cleanups; + char *full_pathname = NULL; + int fd; ++ int is_python; + + if (file == NULL || *file == 0) + { +@@ -471,8 +475,16 @@ source_script (char *file, int from_tty) + } + } + ++ is_python = source_python; ++ if (strlen (file) > 3 && !strcmp (&file[strlen (file) - 3], ".py")) ++ is_python = 1; ++ + stream = fdopen (fd, FOPEN_RT); +- script_from_file (stream, file); ++ ++ if (is_python) ++ source_python_script (stream, file); ++ else ++ script_from_file (stream, file); + + do_cleanups (old_cleanups); + } +@@ -486,15 +498,30 @@ source_verbose_cleanup (void *old_value) + xfree (old_value); + } + ++/* A helper for source_command. Look for an argument in *ARGS. ++ Update *ARGS by stripping leading whitespace. If an argument is ++ found, return it (a character). Otherwise, return 0. */ ++static int ++find_argument (char **args) ++{ ++ int result = 0; ++ while (isspace ((*args)[0])) ++ ++*args; ++ if ((*args)[0] == '-' && isalpha ((*args)[1])) ++ { ++ result = (*args)[1]; ++ *args += 3; ++ } ++ return result; ++} ++ + static void + source_command (char *args, int from_tty) + { + struct cleanup *old_cleanups; +- char *file = args; +- int *old_source_verbose = xmalloc (sizeof(int)); + +- *old_source_verbose = source_verbose; +- old_cleanups = make_cleanup (source_verbose_cleanup, old_source_verbose); ++ old_cleanups = make_cleanup_restore_integer (&source_verbose); ++ make_cleanup_restore_integer (&source_python); + + /* -v causes the source command to run in verbose mode. + We still have to be able to handle filenames with spaces in a +@@ -502,23 +529,28 @@ source_command (char *args, int from_tty) + + if (args) + { +- /* Make sure leading white space does not break the comparisons. */ +- while (isspace(args[0])) +- args++; +- +- /* Is -v the first thing in the string? */ +- if (args[0] == '-' && args[1] == 'v' && isspace (args[2])) ++ while (1) + { +- source_verbose = 1; +- +- /* Trim -v and whitespace from the filename. */ +- file = &args[3]; +- while (isspace (file[0])) +- file++; ++ int arg = find_argument (&args); ++ if (!arg) ++ break; ++ switch (arg) ++ { ++ case 'v': ++ source_verbose = 1; ++ break; ++ case 'p': ++ source_python = 1; ++ break; ++ default: ++ error (_("unrecognized option -%c"), arg); ++ } + } + } + +- source_script (file, from_tty); ++ source_script (args, from_tty); ++ ++ do_cleanups (old_cleanups); + } + + +@@ -1282,7 +1314,9 @@ Read commands from a file named FILE.\n\ + Optional -v switch (before the filename) causes each command in\n\ + FILE to be echoed as it is executed.\n\ + Note that the file \"%s\" is read automatically in this way\n\ +-when GDB is started."), gdbinit); ++when GDB is started.\n\ ++Optional -p switch (before the filename) causes FILE to be evaluated\n\ ++as Python code."), gdbinit); + c = add_cmd ("source", class_support, source_command, + source_help_text, &cmdlist); + set_cmd_completer (c, filename_completer); +diff --git a/gdb/cli/cli-dump.c b/gdb/cli/cli-dump.c +index ee29f2a..96e6111 100644 +--- a/gdb/cli/cli-dump.c ++++ b/gdb/cli/cli-dump.c +@@ -296,7 +296,7 @@ dump_value_to_file (char *cmd, char *mode, char *file_format) + + if (VALUE_LVAL (val)) + { +- vaddr = VALUE_ADDRESS (val); ++ vaddr = value_address (val); + } + else + { +diff --git a/gdb/coffread.c b/gdb/coffread.c +index 6059d68..47ee601 100644 +--- a/gdb/coffread.c ++++ b/gdb/coffread.c +@@ -346,7 +346,7 @@ coff_alloc_type (int index) + We will fill it in later if we find out how. */ + if (type == NULL) + { +- type = alloc_type (current_objfile); ++ type = alloc_type (current_objfile, NULL); + *type_addr = type; + } + return type; +@@ -2101,6 +2101,7 @@ static struct sym_fns coff_sym_fns = + coff_new_init, /* sym_new_init: init anything gbl to entire symtab */ + coff_symfile_init, /* sym_init: read initial info, setup for sym_read() */ + coff_symfile_read, /* sym_read: read a symbol file into symtab */ ++ NULL, /* sym_read_psymbols */ + coff_symfile_finish, /* sym_finish: finished with file, cleanup */ + default_symfile_offsets, /* sym_offsets: xlate external to internal form */ + default_symfile_segments, /* sym_segments: Get segment information from +diff --git a/gdb/config.in b/gdb/config.in +index 6aaf77a..0c8ccab 100644 +--- a/gdb/config.in ++++ b/gdb/config.in +@@ -42,6 +42,12 @@ + language is requested. */ + #undef ENABLE_NLS + ++/* Global directory for GDB data files. */ ++#undef GDB_DATADIR ++ ++/* Define if GDB datadir should be relocated when GDB is moved. */ ++#undef GDB_DATADIR_RELOCATABLE ++ + /* Define to be a string naming the default host character set. */ + #undef GDB_DEFAULT_HOST_CHARSET + +@@ -169,12 +175,18 @@ + /* Define if you have the iconv() function. */ + #undef HAVE_ICONV + ++/* Define to 1 if you have the `iconvlist' function. */ ++#undef HAVE_ICONVLIST ++ + /* Define if your compiler supports the #include_next directive. */ + #undef HAVE_INCLUDE_NEXT + + /* Define to 1 if you have the header file. */ + #undef HAVE_INTTYPES_H + ++/* Define if you have and nl_langinfo(CODESET). */ ++#undef HAVE_LANGINFO_CODESET ++ + /* Define if your file defines LC_MESSAGES. */ + #undef HAVE_LC_MESSAGES + +@@ -618,6 +630,9 @@ + 'ptrdiff_t'. */ + #undef PTRDIFF_T_SUFFIX + ++/* Define to install path for Python sources */ ++#undef PYTHONDIR ++ + /* Bug reporting address */ + #undef REPORT_BUGS_TO + +diff --git a/gdb/configure b/gdb/configure +index 7579c84..3a5b582 100755 +--- a/gdb/configure ++++ b/gdb/configure +@@ -314,7 +314,7 @@ ac_subdirs_all="$ac_subdirs_all doc testsuite" + ac_subdirs_all="$ac_subdirs_all gdbtk" + ac_subdirs_all="$ac_subdirs_all multi-ice" + ac_subdirs_all="$ac_subdirs_all gdbserver" +-ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CPP EGREP RANLIB ac_ct_RANLIB build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os am__leading_dot DEPDIR CCDEPMODE MAKE GMAKE_TRUE GMAKE_FALSE SET_MAKE USE_NLS LIBINTL LIBINTL_DEP INCINTL XGETTEXT GMSGFMT POSUB CATALOGS DATADIRNAME INSTOBJEXT GENCAT CATOBJEXT localedir GL_COND_LIBTOOL_TRUE GL_COND_LIBTOOL_FALSE GNULIB_MEMMEM GNULIB_MEMPCPY GNULIB_MEMRCHR GNULIB_STPCPY GNULIB_STPNCPY GNULIB_STRCHRNUL GNULIB_STRDUP GNULIB_STRNDUP GNULIB_STRNLEN GNULIB_STRPBRK GNULIB_STRSEP GNULIB_STRSTR GNULIB_STRCASESTR GNULIB_STRTOK_R GNULIB_MBSLEN GNULIB_MBSNLEN GNULIB_MBSCHR GNULIB_MBSRCHR GNULIB_MBSSTR GNULIB_MBSCASECMP GNULIB_MBSNCASECMP GNULIB_MBSPCASECMP GNULIB_MBSCASESTR GNULIB_MBSCSPN GNULIB_MBSPBRK GNULIB_MBSSPN GNULIB_MBSSEP GNULIB_MBSTOK_R GNULIB_STRERROR GNULIB_STRSIGNAL HAVE_DECL_MEMMEM HAVE_MEMPCPY HAVE_DECL_MEMRCHR HAVE_STPCPY HAVE_STPNCPY HAVE_STRCHRNUL HAVE_DECL_STRDUP HAVE_STRNDUP HAVE_DECL_STRNDUP HAVE_DECL_STRNLEN HAVE_STRPBRK HAVE_STRSEP HAVE_STRCASESTR HAVE_DECL_STRTOK_R HAVE_DECL_STRERROR HAVE_DECL_STRSIGNAL REPLACE_STRERROR REPLACE_STRSIGNAL REPLACE_MEMMEM REPLACE_STRCASESTR REPLACE_STRSTR HAVE_LONG_LONG_INT HAVE_UNSIGNED_LONG_LONG_INT HAVE_INTTYPES_H HAVE_SYS_TYPES_H INCLUDE_NEXT NEXT_STDINT_H HAVE_STDINT_H HAVE_SYS_INTTYPES_H HAVE_SYS_BITYPES_H BITSIZEOF_PTRDIFF_T BITSIZEOF_SIG_ATOMIC_T BITSIZEOF_SIZE_T BITSIZEOF_WCHAR_T BITSIZEOF_WINT_T HAVE_SIGNED_SIG_ATOMIC_T HAVE_SIGNED_WCHAR_T HAVE_SIGNED_WINT_T PTRDIFF_T_SUFFIX SIG_ATOMIC_T_SUFFIX SIZE_T_SUFFIX WCHAR_T_SUFFIX WINT_T_SUFFIX STDINT_H NEXT_STRING_H GNULIB_WCWIDTH HAVE_DECL_WCWIDTH REPLACE_WCWIDTH WCHAR_H HAVE_WCHAR_H NEXT_WCHAR_H LIBGNU_LIBDEPS LIBGNU_LTLIBDEPS GNULIB_STDINT_H PACKAGE INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK AMTAR am__tar am__untar am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH am__fastdepCC_TRUE am__fastdepCC_FALSE subdirs TARGET_OBS PKGVERSION REPORT_BUGS_TO REPORT_BUGS_TEXI LN_S YACC AR ac_ct_AR DLLTOOL ac_ct_DLLTOOL WINDRES ac_ct_WINDRES MIG ac_ct_MIG READLINE READLINE_DEPS READLINE_CFLAGS HAVE_LIBEXPAT LIBEXPAT LTLIBEXPAT PYTHON_CFLAGS ALLOCA CONFIG_LDFLAGS TARGET_SYSTEM_ROOT TARGET_SYSTEM_ROOT_DEFINE WARN_CFLAGS WERROR_CFLAGS SER_HARDWIRE WIN32LIBS LIBGUI GUI_CFLAGS_X WIN32LDAPP TCL_VERSION TCL_PATCH_LEVEL TCL_BIN_DIR TCL_SRC_DIR TCL_LIB_FILE TCL_LIB_FLAG TCL_LIB_SPEC TCL_STUB_LIB_FILE TCL_STUB_LIB_FLAG TCL_STUB_LIB_SPEC TCL_INCLUDE TCL_LIBRARY TCL_DEPS TK_VERSION TK_BIN_DIR TK_SRC_DIR TK_LIB_FILE TK_LIB_FLAG TK_LIB_SPEC TK_STUB_LIB_FILE TK_STUB_LIB_FLAG TK_STUB_LIB_SPEC TK_INCLUDE TK_LIBRARY TK_DEPS TK_XINCLUDES X_CFLAGS X_LDFLAGS X_LIBS GDBTKLIBS GDBTK_CFLAGS GDBTK_SRC_DIR SIM SIM_OBS ENABLE_CFLAGS PROFILE_CFLAGS CONFIG_OBS CONFIG_DEPS CONFIG_SRCS CONFIG_ALL CONFIG_CLEAN CONFIG_INSTALL CONFIG_UNINSTALL target_subdir frags nm_h LIBICONV LIBOBJS LTLIBOBJS gl_LIBOBJS gl_LTLIBOBJS gltests_LIBOBJS gltests_LTLIBOBJS' ++ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CPP EGREP RANLIB ac_ct_RANLIB build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os am__leading_dot DEPDIR CCDEPMODE MAKE GMAKE_TRUE GMAKE_FALSE SET_MAKE USE_NLS LIBINTL LIBINTL_DEP INCINTL XGETTEXT GMSGFMT POSUB CATALOGS DATADIRNAME INSTOBJEXT GENCAT CATOBJEXT localedir GL_COND_LIBTOOL_TRUE GL_COND_LIBTOOL_FALSE GNULIB_MEMMEM GNULIB_MEMPCPY GNULIB_MEMRCHR GNULIB_STPCPY GNULIB_STPNCPY GNULIB_STRCHRNUL GNULIB_STRDUP GNULIB_STRNDUP GNULIB_STRNLEN GNULIB_STRPBRK GNULIB_STRSEP GNULIB_STRSTR GNULIB_STRCASESTR GNULIB_STRTOK_R GNULIB_MBSLEN GNULIB_MBSNLEN GNULIB_MBSCHR GNULIB_MBSRCHR GNULIB_MBSSTR GNULIB_MBSCASECMP GNULIB_MBSNCASECMP GNULIB_MBSPCASECMP GNULIB_MBSCASESTR GNULIB_MBSCSPN GNULIB_MBSPBRK GNULIB_MBSSPN GNULIB_MBSSEP GNULIB_MBSTOK_R GNULIB_STRERROR GNULIB_STRSIGNAL HAVE_DECL_MEMMEM HAVE_MEMPCPY HAVE_DECL_MEMRCHR HAVE_STPCPY HAVE_STPNCPY HAVE_STRCHRNUL HAVE_DECL_STRDUP HAVE_STRNDUP HAVE_DECL_STRNDUP HAVE_DECL_STRNLEN HAVE_STRPBRK HAVE_STRSEP HAVE_STRCASESTR HAVE_DECL_STRTOK_R HAVE_DECL_STRERROR HAVE_DECL_STRSIGNAL REPLACE_STRERROR REPLACE_STRSIGNAL REPLACE_MEMMEM REPLACE_STRCASESTR REPLACE_STRSTR HAVE_LONG_LONG_INT HAVE_UNSIGNED_LONG_LONG_INT HAVE_INTTYPES_H HAVE_SYS_TYPES_H INCLUDE_NEXT NEXT_STDINT_H HAVE_STDINT_H HAVE_SYS_INTTYPES_H HAVE_SYS_BITYPES_H BITSIZEOF_PTRDIFF_T BITSIZEOF_SIG_ATOMIC_T BITSIZEOF_SIZE_T BITSIZEOF_WCHAR_T BITSIZEOF_WINT_T HAVE_SIGNED_SIG_ATOMIC_T HAVE_SIGNED_WCHAR_T HAVE_SIGNED_WINT_T PTRDIFF_T_SUFFIX SIG_ATOMIC_T_SUFFIX SIZE_T_SUFFIX WCHAR_T_SUFFIX WINT_T_SUFFIX STDINT_H NEXT_STRING_H GNULIB_WCWIDTH HAVE_DECL_WCWIDTH REPLACE_WCWIDTH WCHAR_H HAVE_WCHAR_H NEXT_WCHAR_H LIBGNU_LIBDEPS LIBGNU_LTLIBDEPS GNULIB_STDINT_H PACKAGE INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK AMTAR am__tar am__untar am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH am__fastdepCC_TRUE am__fastdepCC_FALSE GDB_DATADIR_PATH pythondir subdirs TARGET_OBS PKGVERSION REPORT_BUGS_TO REPORT_BUGS_TEXI LN_S YACC AR ac_ct_AR DLLTOOL ac_ct_DLLTOOL WINDRES ac_ct_WINDRES MIG ac_ct_MIG LIBICONV LIBICONV_INCLUDE LIBICONV_LIBDIR READLINE READLINE_DEPS READLINE_CFLAGS HAVE_LIBEXPAT LIBEXPAT LTLIBEXPAT PYTHON_CFLAGS ALLOCA CONFIG_LDFLAGS TARGET_SYSTEM_ROOT TARGET_SYSTEM_ROOT_DEFINE WARN_CFLAGS WERROR_CFLAGS SER_HARDWIRE WIN32LIBS LIBGUI GUI_CFLAGS_X WIN32LDAPP TCL_VERSION TCL_PATCH_LEVEL TCL_BIN_DIR TCL_SRC_DIR TCL_LIB_FILE TCL_LIB_FLAG TCL_LIB_SPEC TCL_STUB_LIB_FILE TCL_STUB_LIB_FLAG TCL_STUB_LIB_SPEC TCL_INCLUDE TCL_LIBRARY TCL_DEPS TK_VERSION TK_BIN_DIR TK_SRC_DIR TK_LIB_FILE TK_LIB_FLAG TK_LIB_SPEC TK_STUB_LIB_FILE TK_STUB_LIB_FLAG TK_STUB_LIB_SPEC TK_INCLUDE TK_LIBRARY TK_DEPS TK_XINCLUDES X_CFLAGS X_LDFLAGS X_LIBS GDBTKLIBS GDBTK_CFLAGS GDBTK_SRC_DIR SIM SIM_OBS ENABLE_CFLAGS PROFILE_CFLAGS CONFIG_OBS CONFIG_DEPS CONFIG_SRCS CONFIG_ALL CONFIG_CLEAN CONFIG_INSTALL CONFIG_UNINSTALL target_subdir frags nm_h LIBOBJS LTLIBOBJS gl_LIBOBJS gl_LTLIBOBJS gltests_LIBOBJS gltests_LTLIBOBJS' + ac_subst_files='host_makefile_frag' + ac_pwd=`pwd` + +@@ -882,9 +882,14 @@ Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-separate-debug-dir=path Look for global separate debug info in this path LIBDIR/debug ++ --with-gdb-datadir look for global separate data files in this path ++ [DATADIR/gdb] ++ --with-pythondir install Python data files in this path ++ [DATADIR/gdb/python] + --with-libunwind Use libunwind frame unwinding support + --with-pkgversion=PKG Use PKG in the version string in place of "GDB" + --with-bugurl=URL Direct users to URL to report a bug ++ --with-libiconv-prefix=DIR search for libiconv in DIR/include and DIR/lib + --with-system-readline use installed readline library + --with-expat include expat support (auto/yes/no) + --with-gnu-ld assume the C compiler uses GNU ld default=no +@@ -899,7 +904,6 @@ Optional Packages: + --with-tcl directory containing tcl configuration (tclConfig.sh) + --with-tk directory containing tk configuration (tkConfig.sh) + --with-x use the X Window System +- --with-libiconv-prefix=DIR search for libiconv in DIR/include and DIR/lib + + Some influential environment variables: + CC C compiler command +@@ -7130,6 +7134,75 @@ _ACEOF + ;; + esac + ++# GDB's datadir relocation ++ ++gdbdatadir=${datadir}/gdb ++ ++ ++# Check whether --with-gdb-datadir or --without-gdb-datadir was given. ++if test "${with_gdb_datadir+set}" = set; then ++ withval="$with_gdb_datadir" ++ gdbdatadir="${withval}" ++fi; ++ ++ ++ test "x$prefix" = xNONE && prefix="$ac_default_prefix" ++ test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' ++ ac_define_dir=`eval echo $gdbdatadir` ++ ac_define_dir=`eval echo $ac_define_dir` ++ ++cat >>confdefs.h <<_ACEOF ++#define GDB_DATADIR "$ac_define_dir" ++_ACEOF ++ ++ ++ ++if test "x$exec_prefix" = xNONE || test "x$exec_prefix" = 'x${prefix}'; then ++ if test "x$prefix" = xNONE; then ++ test_prefix=/usr/local ++ else ++ test_prefix=$prefix ++ fi ++else ++ test_prefix=$exec_prefix ++fi ++ ++case ${gdbdatadir} in ++ "${test_prefix}"|"${test_prefix}/"*|\ ++ '${exec_prefix}'|'${exec_prefix}/'*) ++ ++cat >>confdefs.h <<\_ACEOF ++#define GDB_DATADIR_RELOCATABLE 1 ++_ACEOF ++ ++ ;; ++esac ++GDB_DATADIR_PATH=${gdbdatadir} ++ ++ ++ ++# Check whether --with-pythondir or --without-pythondir was given. ++if test "${with_pythondir+set}" = set; then ++ withval="$with_pythondir" ++ pythondir="${withval}" ++else ++ pythondir=no ++fi; ++ ++# If the user passed in a path, define it. Otherwise, compute it at ++# runtime based on the possibly-relocatable datadir. ++if test "$pythondir" = "no"; then ++ pythondir='$(GDB_DATADIR_PATH)/python' ++else ++ ++cat >>confdefs.h <<_ACEOF ++#define PYTHONDIR "$pythondir" ++_ACEOF ++ ++fi ++ ++ ++ + + + subdirs="$subdirs doc testsuite" +@@ -9989,6 +10062,226 @@ if test "$ac_cv_search_dlgetmodinfo" != no; then + fi + + ++ ++ ++ ++# Check whether --with-libiconv-prefix or --without-libiconv-prefix was given. ++if test "${with_libiconv_prefix+set}" = set; then ++ withval="$with_libiconv_prefix" ++ ++ for dir in `echo "$withval" | tr : ' '`; do ++ if test -d $dir/include; then LIBICONV_INCLUDE="-I$dir/include"; CPPFLAGS="$CPPFLAGS -I$dir/include"; fi ++ if test -d $dir/lib; then LIBICONV_LIBDIR="-L$dir/lib"; LDFLAGS="$LDFLAGS -L$dir/lib"; fi ++ done ++ ++fi; ++ ++ echo "$as_me:$LINENO: checking for iconv" >&5 ++echo $ECHO_N "checking for iconv... $ECHO_C" >&6 ++if test "${am_cv_func_iconv+set}" = set; then ++ echo $ECHO_N "(cached) $ECHO_C" >&6 ++else ++ ++ am_cv_func_iconv="no, consider installing GNU libiconv" ++ am_cv_lib_iconv=no ++ cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++#include ++#include ++int ++main () ++{ ++iconv_t cd = iconv_open("",""); ++ iconv(cd,NULL,NULL,NULL,NULL); ++ iconv_close(cd); ++ ; ++ return 0; ++} ++_ACEOF ++rm -f conftest.$ac_objext conftest$ac_exeext ++if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 ++ (eval $ac_link) 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } && ++ { ac_try='test -z "$ac_c_werror_flag" ++ || test ! -s conftest.err' ++ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 ++ (eval $ac_try) 2>&5 ++ ac_status=$? ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); }; } && ++ { ac_try='test -s conftest$ac_exeext' ++ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 ++ (eval $ac_try) 2>&5 ++ ac_status=$? ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); }; }; then ++ am_cv_func_iconv=yes ++else ++ echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++fi ++rm -f conftest.err conftest.$ac_objext \ ++ conftest$ac_exeext conftest.$ac_ext ++ if test "$am_cv_func_iconv" != yes; then ++ am_save_LIBS="$LIBS" ++ LIBS="$LIBS -liconv" ++ cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++#include ++#include ++int ++main () ++{ ++iconv_t cd = iconv_open("",""); ++ iconv(cd,NULL,NULL,NULL,NULL); ++ iconv_close(cd); ++ ; ++ return 0; ++} ++_ACEOF ++rm -f conftest.$ac_objext conftest$ac_exeext ++if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 ++ (eval $ac_link) 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } && ++ { ac_try='test -z "$ac_c_werror_flag" ++ || test ! -s conftest.err' ++ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 ++ (eval $ac_try) 2>&5 ++ ac_status=$? ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); }; } && ++ { ac_try='test -s conftest$ac_exeext' ++ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 ++ (eval $ac_try) 2>&5 ++ ac_status=$? ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); }; }; then ++ am_cv_lib_iconv=yes ++ am_cv_func_iconv=yes ++else ++ echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++fi ++rm -f conftest.err conftest.$ac_objext \ ++ conftest$ac_exeext conftest.$ac_ext ++ LIBS="$am_save_LIBS" ++ fi ++ ++fi ++echo "$as_me:$LINENO: result: $am_cv_func_iconv" >&5 ++echo "${ECHO_T}$am_cv_func_iconv" >&6 ++ if test "$am_cv_func_iconv" = yes; then ++ ++cat >>confdefs.h <<\_ACEOF ++#define HAVE_ICONV 1 ++_ACEOF ++ ++ echo "$as_me:$LINENO: checking for iconv declaration" >&5 ++echo $ECHO_N "checking for iconv declaration... $ECHO_C" >&6 ++ if test "${am_cv_proto_iconv+set}" = set; then ++ echo $ECHO_N "(cached) $ECHO_C" >&6 ++else ++ ++ cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++ ++#include ++#include ++extern ++#ifdef __cplusplus ++"C" ++#endif ++#if defined(__STDC__) || defined(__cplusplus) ++size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); ++#else ++size_t iconv(); ++#endif ++ ++int ++main () ++{ ++ ++ ; ++ return 0; ++} ++_ACEOF ++rm -f conftest.$ac_objext ++if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ++ (eval $ac_compile) 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } && ++ { ac_try='test -z "$ac_c_werror_flag" ++ || test ! -s conftest.err' ++ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 ++ (eval $ac_try) 2>&5 ++ ac_status=$? ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); }; } && ++ { ac_try='test -s conftest.$ac_objext' ++ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 ++ (eval $ac_try) 2>&5 ++ ac_status=$? ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); }; }; then ++ am_cv_proto_iconv_arg1="" ++else ++ echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++am_cv_proto_iconv_arg1="const" ++fi ++rm -f conftest.err conftest.$ac_objext conftest.$ac_ext ++ am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);" ++fi ++ ++ am_cv_proto_iconv=`echo "$am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'` ++ echo "$as_me:$LINENO: result: ${ac_t:- ++ }$am_cv_proto_iconv" >&5 ++echo "${ECHO_T}${ac_t:- ++ }$am_cv_proto_iconv" >&6 ++ ++cat >>confdefs.h <<_ACEOF ++#define ICONV_CONST $am_cv_proto_iconv_arg1 ++_ACEOF ++ ++ fi ++ LIBICONV= ++ if test "$am_cv_lib_iconv" = yes; then ++ LIBICONV="-liconv" ++ fi ++ ++ ++ ++ ++ + # On alpha-osf, it appears that libtermcap and libcurses are not compatible. + # There is a very specific comment in /usr/include/curses.h explaining that + # termcap routines built into libcurses must not be used. +@@ -11418,6 +11711,8 @@ _ACEOF + CONFIG_OBS="$CONFIG_OBS \$(SUBDIR_PYTHON_OBS)" + CONFIG_DEPS="$CONFIG_DEPS \$(SUBDIR_PYTHON_DEPS)" + CONFIG_SRCS="$CONFIG_SRCS \$(SUBDIR_PYTHON_SRCS)" ++ CONFIG_INSTALL="$CONFIG_INSTALL install-python" ++ CONFIG_UNINSTALL="$CONFIG_UNINSTALL uninstall-python" + ENABLE_CFLAGS="$ENABLE_CFLAGS \$(SUBDIR_PYTHON_CFLAGS)" + + # Flags needed to compile Python code (taken from python-config --cflags). +@@ -15445,10 +15740,11 @@ fi + + + ++ + for ac_func in canonicalize_file_name realpath getrusage getuid \ + getgid poll pread64 sbrk setpgid setpgrp setsid \ + sigaction sigprocmask sigsetmask socketpair syscall \ +- ttrace wborder setlocale ++ ttrace wborder setlocale iconvlist + do + as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` + echo "$as_me:$LINENO: checking for $ac_func" >&5 +@@ -15550,6 +15846,70 @@ fi + done + + ++ echo "$as_me:$LINENO: checking for nl_langinfo and CODESET" >&5 ++echo $ECHO_N "checking for nl_langinfo and CODESET... $ECHO_C" >&6 ++if test "${am_cv_langinfo_codeset+set}" = set; then ++ echo $ECHO_N "(cached) $ECHO_C" >&6 ++else ++ cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++#include ++int ++main () ++{ ++char* cs = nl_langinfo(CODESET); ++ ; ++ return 0; ++} ++_ACEOF ++rm -f conftest.$ac_objext conftest$ac_exeext ++if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 ++ (eval $ac_link) 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } && ++ { ac_try='test -z "$ac_c_werror_flag" ++ || test ! -s conftest.err' ++ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 ++ (eval $ac_try) 2>&5 ++ ac_status=$? ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); }; } && ++ { ac_try='test -s conftest$ac_exeext' ++ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 ++ (eval $ac_try) 2>&5 ++ ac_status=$? ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); }; }; then ++ am_cv_langinfo_codeset=yes ++else ++ echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++am_cv_langinfo_codeset=no ++fi ++rm -f conftest.err conftest.$ac_objext \ ++ conftest$ac_exeext conftest.$ac_ext ++ ++fi ++echo "$as_me:$LINENO: result: $am_cv_langinfo_codeset" >&5 ++echo "${ECHO_T}$am_cv_langinfo_codeset" >&6 ++ if test $am_cv_langinfo_codeset = yes; then ++ ++cat >>confdefs.h <<\_ACEOF ++#define HAVE_LANGINFO_CODESET 1 ++_ACEOF ++ ++ fi ++ ++ + # Check the return and argument types of ptrace. No canned test for + # this, so roll our own. + gdb_ptrace_headers=' +@@ -20776,230 +21136,11 @@ done + + + +- + cat >>confdefs.h <<\_ACEOF +-#define GDB_DEFAULT_HOST_CHARSET "ISO-8859-1" ++#define GDB_DEFAULT_HOST_CHARSET "UTF-8" + _ACEOF + + +- +- +- +-# Check whether --with-libiconv-prefix or --without-libiconv-prefix was given. +-if test "${with_libiconv_prefix+set}" = set; then +- withval="$with_libiconv_prefix" +- +- for dir in `echo "$withval" | tr : ' '`; do +- if test -d $dir/include; then CPPFLAGS="$CPPFLAGS -I$dir/include"; fi +- if test -d $dir/lib; then LDFLAGS="$LDFLAGS -L$dir/lib"; fi +- done +- +-fi; +- +- echo "$as_me:$LINENO: checking for iconv" >&5 +-echo $ECHO_N "checking for iconv... $ECHO_C" >&6 +-if test "${am_cv_func_iconv+set}" = set; then +- echo $ECHO_N "(cached) $ECHO_C" >&6 +-else +- +- am_cv_func_iconv="no, consider installing GNU libiconv" +- am_cv_lib_iconv=no +- cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +-#include +-#include +-int +-main () +-{ +-iconv_t cd = iconv_open("",""); +- iconv(cd,NULL,NULL,NULL,NULL); +- iconv_close(cd); +- ; +- return 0; +-} +-_ACEOF +-rm -f conftest.$ac_objext conftest$ac_exeext +-if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 +- (eval $ac_link) 2>conftest.er1 +- ac_status=$? +- grep -v '^ *+' conftest.er1 >conftest.err +- rm -f conftest.er1 +- cat conftest.err >&5 +- echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } && +- { ac_try='test -z "$ac_c_werror_flag" +- || test ! -s conftest.err' +- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 +- (eval $ac_try) 2>&5 +- ac_status=$? +- echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); }; } && +- { ac_try='test -s conftest$ac_exeext' +- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 +- (eval $ac_try) 2>&5 +- ac_status=$? +- echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); }; }; then +- am_cv_func_iconv=yes +-else +- echo "$as_me: failed program was:" >&5 +-sed 's/^/| /' conftest.$ac_ext >&5 +- +-fi +-rm -f conftest.err conftest.$ac_objext \ +- conftest$ac_exeext conftest.$ac_ext +- if test "$am_cv_func_iconv" != yes; then +- am_save_LIBS="$LIBS" +- LIBS="$LIBS -liconv" +- cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +-#include +-#include +-int +-main () +-{ +-iconv_t cd = iconv_open("",""); +- iconv(cd,NULL,NULL,NULL,NULL); +- iconv_close(cd); +- ; +- return 0; +-} +-_ACEOF +-rm -f conftest.$ac_objext conftest$ac_exeext +-if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 +- (eval $ac_link) 2>conftest.er1 +- ac_status=$? +- grep -v '^ *+' conftest.er1 >conftest.err +- rm -f conftest.er1 +- cat conftest.err >&5 +- echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } && +- { ac_try='test -z "$ac_c_werror_flag" +- || test ! -s conftest.err' +- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 +- (eval $ac_try) 2>&5 +- ac_status=$? +- echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); }; } && +- { ac_try='test -s conftest$ac_exeext' +- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 +- (eval $ac_try) 2>&5 +- ac_status=$? +- echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); }; }; then +- am_cv_lib_iconv=yes +- am_cv_func_iconv=yes +-else +- echo "$as_me: failed program was:" >&5 +-sed 's/^/| /' conftest.$ac_ext >&5 +- +-fi +-rm -f conftest.err conftest.$ac_objext \ +- conftest$ac_exeext conftest.$ac_ext +- LIBS="$am_save_LIBS" +- fi +- +-fi +-echo "$as_me:$LINENO: result: $am_cv_func_iconv" >&5 +-echo "${ECHO_T}$am_cv_func_iconv" >&6 +- if test "$am_cv_func_iconv" = yes; then +- +-cat >>confdefs.h <<\_ACEOF +-#define HAVE_ICONV 1 +-_ACEOF +- +- echo "$as_me:$LINENO: checking for iconv declaration" >&5 +-echo $ECHO_N "checking for iconv declaration... $ECHO_C" >&6 +- if test "${am_cv_proto_iconv+set}" = set; then +- echo $ECHO_N "(cached) $ECHO_C" >&6 +-else +- +- cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +- +-#include +-#include +-extern +-#ifdef __cplusplus +-"C" +-#endif +-#if defined(__STDC__) || defined(__cplusplus) +-size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); +-#else +-size_t iconv(); +-#endif +- +-int +-main () +-{ +- +- ; +- return 0; +-} +-_ACEOF +-rm -f conftest.$ac_objext +-if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 +- (eval $ac_compile) 2>conftest.er1 +- ac_status=$? +- grep -v '^ *+' conftest.er1 >conftest.err +- rm -f conftest.er1 +- cat conftest.err >&5 +- echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } && +- { ac_try='test -z "$ac_c_werror_flag" +- || test ! -s conftest.err' +- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 +- (eval $ac_try) 2>&5 +- ac_status=$? +- echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); }; } && +- { ac_try='test -s conftest.$ac_objext' +- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 +- (eval $ac_try) 2>&5 +- ac_status=$? +- echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); }; }; then +- am_cv_proto_iconv_arg1="" +-else +- echo "$as_me: failed program was:" >&5 +-sed 's/^/| /' conftest.$ac_ext >&5 +- +-am_cv_proto_iconv_arg1="const" +-fi +-rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +- am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);" +-fi +- +- am_cv_proto_iconv=`echo "$am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'` +- echo "$as_me:$LINENO: result: ${ac_t:- +- }$am_cv_proto_iconv" >&5 +-echo "${ECHO_T}${ac_t:- +- }$am_cv_proto_iconv" >&6 +- +-cat >>confdefs.h <<_ACEOF +-#define ICONV_CONST $am_cv_proto_iconv_arg1 +-_ACEOF +- +- fi +- LIBICONV= +- if test "$am_cv_lib_iconv" = yes; then +- LIBICONV="-liconv" +- fi +- +- +- + ac_config_files="$ac_config_files Makefile .gdbinit:gdbinit.in gnulib/Makefile" + ac_config_commands="$ac_config_commands default" + cat >confcache <<\_ACEOF +@@ -21865,6 +22006,8 @@ s,@AMDEP_FALSE@,$AMDEP_FALSE,;t t + s,@AMDEPBACKSLASH@,$AMDEPBACKSLASH,;t t + s,@am__fastdepCC_TRUE@,$am__fastdepCC_TRUE,;t t + s,@am__fastdepCC_FALSE@,$am__fastdepCC_FALSE,;t t ++s,@GDB_DATADIR_PATH@,$GDB_DATADIR_PATH,;t t ++s,@pythondir@,$pythondir,;t t + s,@subdirs@,$subdirs,;t t + s,@TARGET_OBS@,$TARGET_OBS,;t t + s,@PKGVERSION@,$PKGVERSION,;t t +@@ -21880,6 +22023,9 @@ s,@WINDRES@,$WINDRES,;t t + s,@ac_ct_WINDRES@,$ac_ct_WINDRES,;t t + s,@MIG@,$MIG,;t t + s,@ac_ct_MIG@,$ac_ct_MIG,;t t ++s,@LIBICONV@,$LIBICONV,;t t ++s,@LIBICONV_INCLUDE@,$LIBICONV_INCLUDE,;t t ++s,@LIBICONV_LIBDIR@,$LIBICONV_LIBDIR,;t t + s,@READLINE@,$READLINE,;t t + s,@READLINE_DEPS@,$READLINE_DEPS,;t t + s,@READLINE_CFLAGS@,$READLINE_CFLAGS,;t t +@@ -21944,7 +22090,6 @@ s,@CONFIG_UNINSTALL@,$CONFIG_UNINSTALL,;t t + s,@target_subdir@,$target_subdir,;t t + s,@frags@,$frags,;t t + s,@nm_h@,$nm_h,;t t +-s,@LIBICONV@,$LIBICONV,;t t + s,@LIBOBJS@,$LIBOBJS,;t t + s,@LTLIBOBJS@,$LTLIBOBJS,;t t + s,@gl_LIBOBJS@,$gl_LIBOBJS,;t t +diff --git a/gdb/configure.ac b/gdb/configure.ac +index 3f81ff2..ff76053 100644 +--- a/gdb/configure.ac ++++ b/gdb/configure.ac +@@ -1,6 +1,6 @@ + dnl Autoconf configure script for GDB, the GNU debugger. + dnl Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +-dnl 2005, 2006, 2007, 2008 ++dnl 2005, 2006, 2007, 2008, 2009 + dnl Free Software Foundation, Inc. + dnl + dnl This file is part of GDB. +@@ -118,6 +118,51 @@ case ${debugdir} in + ;; + esac + ++# GDB's datadir relocation ++ ++gdbdatadir=${datadir}/gdb ++ ++AC_ARG_WITH([gdb-datadir], ++ [AS_HELP_STRING([--with-gdb-datadir], ++ [look for global separate data files in this path [DATADIR/gdb]])], [gdbdatadir="${withval}"]) ++ ++AC_DEFINE_DIR(GDB_DATADIR, gdbdatadir, ++ [Global directory for GDB data files. ]) ++ ++if test "x$exec_prefix" = xNONE || test "x$exec_prefix" = 'x${prefix}'; then ++ if test "x$prefix" = xNONE; then ++ test_prefix=/usr/local ++ else ++ test_prefix=$prefix ++ fi ++else ++ test_prefix=$exec_prefix ++fi ++ ++case ${gdbdatadir} in ++ "${test_prefix}"|"${test_prefix}/"*|\ ++ '${exec_prefix}'|'${exec_prefix}/'*) ++ AC_DEFINE(GDB_DATADIR_RELOCATABLE, 1, [Define if GDB datadir should be relocated when GDB is moved.]) ++ ;; ++esac ++GDB_DATADIR_PATH=${gdbdatadir} ++AC_SUBST(GDB_DATADIR_PATH) ++ ++AC_ARG_WITH([pythondir], ++ [AS_HELP_STRING([--with-pythondir], ++ [install Python data files in this path [DATADIR/gdb/python]])], [pythondir="${withval}"], [pythondir=no]) ++ ++# If the user passed in a path, define it. Otherwise, compute it at ++# runtime based on the possibly-relocatable datadir. ++if test "$pythondir" = "no"; then ++ pythondir='$(GDB_DATADIR_PATH)/python' ++else ++ AC_DEFINE_UNQUOTED(PYTHONDIR, "$pythondir", ++ [Define to install path for Python sources]) ++fi ++AC_SUBST(pythondir) ++ ++ + AC_CONFIG_SUBDIRS(doc testsuite) + + # Check whether to support alternative target configurations +@@ -430,6 +475,8 @@ AC_SEARCH_LIBS(zlibVersion, z, [AC_CHECK_HEADERS(zlib.h)]) + # On HP/UX we may need libxpdl for dlgetmodinfo (used by solib-pa64.c). + AC_SEARCH_LIBS(dlgetmodinfo, [dl xpdl]) + ++AM_ICONV ++ + # On alpha-osf, it appears that libtermcap and libcurses are not compatible. + # There is a very specific comment in /usr/include/curses.h explaining that + # termcap routines built into libcurses must not be used. +@@ -649,6 +696,8 @@ if test "${have_libpython}" = yes; then + CONFIG_OBS="$CONFIG_OBS \$(SUBDIR_PYTHON_OBS)" + CONFIG_DEPS="$CONFIG_DEPS \$(SUBDIR_PYTHON_DEPS)" + CONFIG_SRCS="$CONFIG_SRCS \$(SUBDIR_PYTHON_SRCS)" ++ CONFIG_INSTALL="$CONFIG_INSTALL install-python" ++ CONFIG_UNINSTALL="$CONFIG_UNINSTALL uninstall-python" + ENABLE_CFLAGS="$ENABLE_CFLAGS \$(SUBDIR_PYTHON_CFLAGS)" + + # Flags needed to compile Python code (taken from python-config --cflags). +@@ -776,7 +825,8 @@ AC_FUNC_VFORK + AC_CHECK_FUNCS([canonicalize_file_name realpath getrusage getuid \ + getgid poll pread64 sbrk setpgid setpgrp setsid \ + sigaction sigprocmask sigsetmask socketpair syscall \ +- ttrace wborder setlocale]) ++ ttrace wborder setlocale iconvlist]) ++AM_LANGINFO_CODESET + + # Check the return and argument types of ptrace. No canned test for + # this, so roll our own. +@@ -1930,17 +1980,10 @@ dnl Check for exe extension set on certain hosts (e.g. Win32) + AC_EXEEXT + + dnl Detect the character set used by this host. +- +-dnl At the moment, we just assume it's ISO-8859-1 (which is a +-dnl superset of ASCII containing the characters needed for French, +-dnl German, Spanish, Italian, and possibly others), but if were +-dnl *were* to support any host character sets other than ISO-8859-1, +-dnl here's where we'd detect it. +-AC_DEFINE(GDB_DEFAULT_HOST_CHARSET, "ISO-8859-1", ++dnl At the moment, we just assume it's UTF-8. ++AC_DEFINE(GDB_DEFAULT_HOST_CHARSET, "UTF-8", + [Define to be a string naming the default host character set.]) + +-AM_ICONV +- + AC_OUTPUT(Makefile .gdbinit:gdbinit.in gnulib/Makefile, + [ + dnl Autoconf doesn't provide a mechanism for modifying definitions +diff --git a/gdb/configure.tgt b/gdb/configure.tgt +index 65c3e25..f0cca7d 100644 +--- a/gdb/configure.tgt ++++ b/gdb/configure.tgt +@@ -36,7 +36,7 @@ alpha*-*-osf*) + alpha*-*-linux*) + # Target: Little-endian Alpha running Linux + gdb_target_obs="alpha-tdep.o alpha-mdebug-tdep.o alpha-linux-tdep.o \ +- solib.o solib-svr4.o" ++ solib.o solib-svr4.o linux-tdep.o" + ;; + alpha*-*-freebsd* | alpha*-*-kfreebsd*-gnu) + # Target: FreeBSD/alpha +@@ -63,7 +63,7 @@ alpha*-*-*) + am33_2.0*-*-linux*) + # Target: Matsushita mn10300 (AM33) running Linux + gdb_target_obs="mn10300-tdep.o mn10300-linux-tdep.o corelow.o \ +- solib.o solib-svr4.o" ++ solib.o solib-svr4.o linux-tdep.o" + ;; + + arm*-wince-pe | arm*-*-mingw32ce*) +@@ -128,7 +128,7 @@ hppa*-*-hpux*) + hppa*-*-linux*) + # Target: HP PA-RISC running Linux + gdb_target_obs="hppa-tdep.o hppa-linux-tdep.o glibc-tdep.o \ +- solib.o solib-svr4.o symfile-mem.o" ++ solib.o solib-svr4.o symfile-mem.o linux-tdep.o" + ;; + hppa*-*-netbsd*) + # Target: NetBSD/hppa +@@ -218,7 +218,7 @@ i[34567]86-*-*) + ia64-*-linux*) + # Target: Intel IA-64 running GNU/Linux + gdb_target_obs="ia64-tdep.o ia64-linux-tdep.o \ +- solib.o solib-svr4.o symfile-mem.o" ++ solib.o solib-svr4.o symfile-mem.o linux-tdep.o" + build_gdbserver=yes + ;; + ia64*-*-*) +@@ -242,7 +242,8 @@ m32c-*-*) + m32r*-*-linux*) + # Target: Renesas M32R running GNU/Linux + gdb_target_obs="m32r-tdep.o m32r-linux-tdep.o remote-m32r-sdi.o \ +- glibc-tdep.o solib.o solib-svr4.o symfile-mem.o" ++ glibc-tdep.o solib.o solib-svr4.o symfile-mem.o \ ++ linux-tdep.o" + gdb_sim=../sim/m32r/libsim.a + build_gdbserver=yes + ;; +@@ -267,7 +268,7 @@ fido-*-elf*) + m68*-*-linux*) + # Target: Motorola m68k with a.out and ELF + gdb_target_obs="m68k-tdep.o m68klinux-tdep.o solib.o solib-svr4.o \ +- glibc-tdep.o symfile-mem.o" ++ glibc-tdep.o symfile-mem.o linux-tdep.o" + build_gdbserver=yes + ;; + m68*-*-netbsd* | m68*-*-knetbsd*-gnu) +@@ -303,7 +304,8 @@ mips*-sgi-irix6*) + mips*-*-linux*) + # Target: Linux/MIPS + gdb_target_obs="mips-tdep.o mips-linux-tdep.o glibc-tdep.o \ +- corelow.o solib.o solib-svr4.o symfile-mem.o" ++ corelow.o solib.o solib-svr4.o symfile-mem.o \ ++ linux-tdep.o" + gdb_sim=../sim/mips/libsim.a + build_gdbserver=yes + ;; +@@ -354,7 +356,8 @@ powerpc-*-aix* | rs6000-*-*) + powerpc-*-linux* | powerpc64-*-linux*) + # Target: PowerPC running Linux + gdb_target_obs="rs6000-tdep.o ppc-linux-tdep.o ppc-sysv-tdep.o \ +- solib.o solib-svr4.o corelow.o symfile-mem.o" ++ solib.o solib-svr4.o corelow.o symfile-mem.o \ ++ linux-tdep.o" + gdb_sim=../sim/ppc/libsim.a + build_gdbserver=yes + ;; +@@ -381,7 +384,8 @@ score-*-*) + sh*-*-linux*) + # Target: GNU/Linux Super-H + gdb_target_obs="sh-tdep.o sh64-tdep.o sh-linux-tdep.o monitor.o \ +- dsrec.o solib.o solib-svr4.o symfile-mem.o glibc-tdep.o" ++ dsrec.o solib.o solib-svr4.o symfile-mem.o glibc-tdep.o \ ++ linux-tdep.o" + gdb_sim=../sim/sh/libsim.a + build_gdbserver=yes + ;; +@@ -409,13 +413,14 @@ sh*) + sparc-*-linux*) + # Target: GNU/Linux SPARC + gdb_target_obs="sparc-tdep.o sparc-sol2-tdep.o sol2-tdep.o \ +- sparc-linux-tdep.o solib.o solib-svr4.o symfile-mem.o" ++ sparc-linux-tdep.o solib.o solib-svr4.o symfile-mem.o \ ++ linux-tdep.o" + ;; + sparc64-*-linux*) + # Target: GNU/Linux UltraSPARC + gdb_target_obs="sparc64-tdep.o sparc64-sol2-tdep.o sol2-tdep.o \ + sparc64-linux-tdep.o sparc-tdep.o sparc-sol2-tdep.o \ +- sparc-linux-tdep.o solib.o solib-svr4.o" ++ sparc-linux-tdep.o solib.o solib-svr4.o linux-tdep.o" + build_gdbserver=yes + ;; + sparc*-*-freebsd* | sparc*-*-kfreebsd*-gnu) +@@ -542,7 +547,8 @@ x86_64-*-openbsd*) + xtensa*-*-linux*) gdb_target=linux + # Target: GNU/Linux Xtensa + gdb_target_obs="xtensa-tdep.o xtensa-config.o xtensa-linux-tdep.o \ +- solib.o solib-svr4.o corelow.o symfile-mem.o" ++ solib.o solib-svr4.o corelow.o symfile-mem.o \ ++ linux-tdep.o" + build_gdbserver=yes + ;; + xtensa*) +diff --git a/gdb/cp-name-parser.y b/gdb/cp-name-parser.y +index 5f5ee3a..a8f8f30 100644 +--- a/gdb/cp-name-parser.y ++++ b/gdb/cp-name-parser.y +@@ -1,7 +1,6 @@ + /* YACC parser for C++ names, for GDB. + +- Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009 +- Free Software Foundation, Inc. ++ Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009 Free Software Foundation, Inc. + + Parts of the lexer are based on c-exp.y from GDB. + +@@ -501,7 +500,7 @@ operator : OPERATOR NEW + | OPERATOR ARROW + { $$ = make_operator ("->", 2); } + | OPERATOR '(' ')' +- { $$ = make_operator ("()", 0); } ++ { $$ = make_operator ("()", 2); } + | OPERATOR '[' ']' + { $$ = make_operator ("[]", 2); } + ; +diff --git a/gdb/cp-namespace.c b/gdb/cp-namespace.c +index c6c5617..4b84348 100644 +--- a/gdb/cp-namespace.c ++++ b/gdb/cp-namespace.c +@@ -30,26 +30,13 @@ + #include "dictionary.h" + #include "command.h" + #include "frame.h" ++#include "buildsym.h" + + /* List of using directives that are active in the current file. */ + +-static struct using_direct *using_list; +- +-static struct using_direct *cp_add_using (const char *name, +- unsigned int inner_len, +- unsigned int outer_len, +- struct using_direct *next); +- + static struct using_direct *cp_copy_usings (struct using_direct *using, + struct obstack *obstack); + +-static struct symbol *lookup_namespace_scope (const char *name, +- const char *linkage_name, +- const struct block *block, +- const domain_enum domain, +- const char *scope, +- int scope_len); +- + static struct symbol *lookup_symbol_file (const char *name, + const char *linkage_name, + const struct block *block, +@@ -78,31 +65,6 @@ static struct symbol *lookup_possible_namespace_symbol (const char *name); + + static void maintenance_cplus_namespace (char *args, int from_tty); + +-/* Set up support for dealing with C++ namespace info in the current +- symtab. */ +- +-void cp_initialize_namespace () +-{ +- using_list = NULL; +-} +- +-/* Add all the using directives we've gathered to the current symtab. +- STATIC_BLOCK should be the symtab's static block; OBSTACK is used +- for allocation. */ +- +-void +-cp_finalize_namespace (struct block *static_block, +- struct obstack *obstack) +-{ +- if (using_list != NULL) +- { +- block_set_using (static_block, +- cp_copy_usings (using_list, obstack), +- obstack); +- using_list = NULL; +- } +-} +- + /* Check to see if SYMBOL refers to an object contained within an + anonymous namespace; if so, add an appropriate using directive. */ + +@@ -136,14 +98,17 @@ cp_scan_for_anonymous_namespaces (const struct symbol *symbol) + "(anonymous namespace)", + ANONYMOUS_NAMESPACE_LEN) == 0) + { ++ int outer_len = (previous_component == 0 ? 0 : previous_component - 2); ++ char outer[outer_len+1]; ++ ++ strncpy(outer, name, outer_len); ++ ++ outer[outer_len] = '\0'; + /* We've found a component of the name that's an + anonymous namespace. So add symbols in it to the + namespace given by the previous component if there is + one, or to the global namespace if there isn't. */ +- cp_add_using_directive (name, +- previous_component == 0 +- ? 0 : previous_component - 2, +- next_component); ++ cp_add_using_directive (outer, name, "", "", 0); + } + /* The "+ 2" is for the "::". */ + previous_component = next_component + 2; +@@ -154,32 +119,27 @@ cp_scan_for_anonymous_namespaces (const struct symbol *symbol) + } + } + +-/* Add a using directive to using_list. NAME is the start of a string +- that should contain the namespaces we want to add as initial +- substrings, OUTER_LENGTH is the end of the outer namespace, and +- INNER_LENGTH is the end of the inner namespace. If the using +- directive in question has already been added, don't add it +- twice. */ ++/* Add a using directive to using_list. If the using directive in question ++ has already been added, don't add it twice. */ + + void +-cp_add_using_directive (const char *name, unsigned int outer_length, +- unsigned int inner_length) ++cp_add_using_directive (const char *outer, const char *inner, const char* alias, ++ const char *declaration, const int line_number) + { + struct using_direct *current; + struct using_direct *new; + + /* Has it already been added? */ + +- for (current = using_list; current != NULL; current = current->next) ++ for (current = using_directives; current != NULL; current = current->next) + { +- if ((strncmp (current->inner, name, inner_length) == 0) +- && (strlen (current->inner) == inner_length) +- && (strlen (current->outer) == outer_length)) ++ if (strcmp (current->inner, inner) == 0 ++ && strcmp (current->outer, outer) == 0) + return; + } + +- using_list = cp_add_using (name, inner_length, outer_length, +- using_list); ++ using_directives = cp_add_using (outer, inner, alias, declaration, ++ line_number,using_directives); + } + + /* Record the namespace that the function defined by SYMBOL was +@@ -230,26 +190,31 @@ cp_is_anonymous (const char *namespace) + != NULL); + } + +-/* Create a new struct using direct whose inner namespace is the +- initial substring of NAME of leng INNER_LEN and whose outer +- namespace is the initial substring of NAME of length OUTER_LENGTH. ++/* Create a new struct using direct whose inner namespace is INNER ++ and whose outer namespace is OUTER. ALIAS is the name of the imported ++ namespace in the current scope. If ALIAS is an empty string then the ++ namespace is known by its original name. + Set its next member in the linked list to NEXT; allocate all memory + using xmalloc. It copies the strings, so NAME can be a temporary + string. */ + +-static struct using_direct * +-cp_add_using (const char *name, +- unsigned int inner_len, +- unsigned int outer_len, ++struct using_direct * ++cp_add_using (const char *outer, ++ const char *inner, ++ const char *alias, ++ const char *declaration, ++ const int line_number, + struct using_direct *next) + { + struct using_direct *retval; + +- gdb_assert (outer_len < inner_len); +- + retval = xmalloc (sizeof (struct using_direct)); +- retval->inner = savestring (name, inner_len); +- retval->outer = savestring (name, outer_len); ++ retval->inner = savestring (inner, strlen(inner)); ++ retval->outer = savestring (outer, strlen(outer)); ++ retval->alias = savestring (alias, strlen(alias)); ++ retval->declaration = savestring (declaration, strlen(declaration)); ++ retval->line_number = line_number; ++ + retval->next = next; + + return retval; +@@ -274,7 +239,11 @@ cp_copy_usings (struct using_direct *using, + retval->inner = obsavestring (using->inner, strlen (using->inner), + obstack); + retval->outer = obsavestring (using->outer, strlen (using->outer), +- obstack); ++ obstack); ++ retval->alias = obsavestring (using->alias, strlen (using->alias), ++ obstack); ++ retval->declaration = obsavestring (using->declaration, strlen (using->declaration), ++ obstack); + retval->next = cp_copy_usings (using->next, obstack); + + xfree (using->inner); +@@ -299,8 +268,14 @@ cp_lookup_symbol_nonlocal (const char *name, + const struct block *block, + const domain_enum domain) + { +- return lookup_namespace_scope (name, linkage_name, block, domain, +- block_scope (block), 0); ++ ++ struct symbol* sym = lookup_namespace_scope(name, linkage_name, block, ++ domain, block_scope(block), 0); ++ ++ if (sym != NULL) ++ return sym; ++ ++ return lookup_symbol_file(name, linkage_name, block, domain, 0); + } + + /* Lookup NAME at namespace scope (or, in C terms, in static and +@@ -318,7 +293,7 @@ cp_lookup_symbol_nonlocal (const char *name, + "A::x", and if that call fails, then the first call looks for + "x". */ + +-static struct symbol * ++struct symbol * + lookup_namespace_scope (const char *name, + const char *linkage_name, + const struct block *block, +@@ -354,10 +329,43 @@ lookup_namespace_scope (const char *name, + namespace = alloca (scope_len + 1); + strncpy (namespace, scope, scope_len); + namespace[scope_len] = '\0'; +- return cp_lookup_symbol_namespace (namespace, name, linkage_name, ++ return cp_lookup_symbol_namespace_incremental (namespace, name, linkage_name, + block, domain); + } + ++/* Searches the for the given NAME in the given NAMESPACE, using import ++ statements implied by the given BLOCK, *and its' parents*. */ ++struct symbol * ++cp_lookup_symbol_namespace_incremental (const char *namespace, ++ const char *name, ++ const char *linkage_name, ++ const struct block *block, ++ const domain_enum domain) ++{ ++ struct symbol *sym; ++ const struct block *global_block = block_global_block (block); ++ ++ /* Check if either no block is specified or it's a global block. */ ++ ++ if (global_block == NULL) ++ return NULL; ++ ++ while (block != global_block) ++ { ++ sym = cp_lookup_symbol_namespace (namespace, name, linkage_name, block, domain); ++ ++ if (sym != NULL) ++ return sym; ++ ++ block = BLOCK_SUPERBLOCK (block); ++ } ++ ++ /* We've reached the global block without finding a result. */ ++ ++ return NULL; ++} ++ ++ + /* Look up NAME in the C++ namespace NAMESPACE, applying the using + directives that are active in BLOCK. Other arguments are as in + cp_lookup_symbol_nonlocal. */ +@@ -370,7 +378,7 @@ cp_lookup_symbol_namespace (const char *namespace, + const domain_enum domain) + { + const struct using_direct *current; +- struct symbol *sym; ++ struct symbol *sym = NULL; + + /* First, go through the using directives. If any of them add new + names to the namespace we're searching in, see if we can find a +@@ -380,15 +388,42 @@ cp_lookup_symbol_namespace (const char *namespace, + current != NULL; + current = current->next) + { +- if (strcmp (namespace, current->outer) == 0) ++ ++ int current_line = find_pc_line (get_frame_pc (get_current_frame ()), 0).line; ++ ++ if (strcmp (namespace, current->outer) == 0 && current->line_number < current_line) + { +- sym = cp_lookup_symbol_namespace (current->inner, +- name, +- linkage_name, +- block, +- domain); +- if (sym != NULL) ++ ++ if(strcmp ("", current->declaration) != 0){ ++ if(strcmp (name, current->declaration) == 0){ ++ sym = cp_lookup_symbol_namespace (current->inner, ++ name, ++ linkage_name, ++ block, ++ domain); ++ } ++ ++ }else{ ++ /* Check for aliases */ ++ if(strcmp (name, current->alias) == 0){ ++ sym = cp_lookup_symbol_namespace (namespace, ++ current->inner, ++ linkage_name, ++ block, ++ domain); ++ }else{ ++ if(strcmp ("", current->alias) == 0){ ++ sym = cp_lookup_symbol_namespace (current->inner, ++ name, ++ linkage_name, ++ block, ++ domain); ++ } ++ } ++ } ++ if (sym != NULL){ + return sym; ++ } + } + } + +@@ -398,8 +433,10 @@ cp_lookup_symbol_namespace (const char *namespace, + + if (namespace[0] == '\0') + { +- return lookup_symbol_file (name, linkage_name, block, +- domain, 0); ++ sym = lookup_symbol_file (name, linkage_name, ++ block, domain, ++ cp_is_anonymous (namespace)); ++ return sym; + } + else + { +diff --git a/gdb/cp-support.c b/gdb/cp-support.c +index bf42636..9f04c86 100644 +--- a/gdb/cp-support.c ++++ b/gdb/cp-support.c +@@ -175,7 +175,8 @@ mangled_name_to_comp (const char *mangled_name, int options, + return ret; + } + +-/* Return the name of the class containing method PHYSNAME. */ ++/* Return the name of the class or namespace containing ++ function, method, or variable PHYSNAME. */ + + char * + cp_class_name_from_physname (const char *physname) +diff --git a/gdb/cp-support.h b/gdb/cp-support.h +index 837ca6c..23f8d5b 100644 +--- a/gdb/cp-support.h ++++ b/gdb/cp-support.h +@@ -38,14 +38,28 @@ struct demangle_component; + + /* This struct is designed to store data from using directives. It + says that names from namespace INNER should be visible within +- namespace OUTER. OUTER should always be a strict initial substring +- of INNER. These form a linked list; NEXT is the next element of +- the list. */ ++ namespace OUTER These form a linked list; NEXT is the next element of ++ the list. ALIAS is set to a non empty string if the imported namespace ++ has been aliased.Eg: ++ namespace C=A::B; ++ ALIAS = "C" ++ DECLARATION is the name of the imported declaration, if this import ++ statement represents one. Eg: ++ using A::x; ++ Where x is variable in namespace A. declaration is set to x. ++*/ + + struct using_direct + { + char *inner; + char *outer; ++ ++ char *alias; ++ ++ char *declaration; ++ ++ int line_number; ++ + struct using_direct *next; + }; + +@@ -54,6 +68,7 @@ struct using_direct + + extern char *cp_canonicalize_string (const char *string); + ++ + extern char *cp_class_name_from_physname (const char *physname); + + extern char *method_name_from_physname (const char *physname); +@@ -76,9 +91,18 @@ extern struct type *cp_lookup_rtti_type (const char *name, + + extern int cp_is_anonymous (const char *namespace); + +-extern void cp_add_using_directive (const char *name, +- unsigned int outer_length, +- unsigned int inner_length); ++extern void cp_add_using_directive (const char *outer, ++ const char *inner, ++ const char *alias, ++ const char *declaration, ++ const int line_number); ++ ++extern struct using_direct *cp_add_using (const char *outer, ++ const char *inner, ++ const char *alias, ++ const char *declaration, ++ const int line_number, ++ struct using_direct *next); + + extern void cp_initialize_namespace (void); + +@@ -98,6 +122,19 @@ extern struct symbol *cp_lookup_symbol_nonlocal (const char *name, + const struct block *block, + const domain_enum domain); + ++extern struct symbol *lookup_namespace_scope (const char *name, ++ const char *linkage_name, ++ const struct block *block, ++ const domain_enum domain, ++ const char *scope, ++ int scope_len); ++ ++extern struct symbol *cp_lookup_symbol_namespace_incremental (const char *namespace, ++ const char *name, ++ const char *linkage_name, ++ const struct block *block, ++ const domain_enum domain); ++ + extern struct symbol *cp_lookup_symbol_namespace (const char *namespace, + const char *name, + const char *linkage_name, +diff --git a/gdb/cp-valprint.c b/gdb/cp-valprint.c +index 8b7d868..dcd32cb 100644 +--- a/gdb/cp-valprint.c ++++ b/gdb/cp-valprint.c +@@ -461,6 +461,7 @@ cp_print_static_field (struct type *type, + if (TYPE_CODE (type) == TYPE_CODE_STRUCT) + { + CORE_ADDR *first_dont_print; ++ CORE_ADDR addr; + int i; + + first_dont_print +@@ -470,7 +471,7 @@ cp_print_static_field (struct type *type, + + while (--i >= 0) + { +- if (VALUE_ADDRESS (val) == first_dont_print[i]) ++ if (value_address (val) == first_dont_print[i]) + { + fputs_filtered ("", +@@ -479,12 +480,13 @@ cp_print_static_field (struct type *type, + } + } + +- obstack_grow (&dont_print_statmem_obstack, (char *) &VALUE_ADDRESS (val), ++ addr = value_address (val); ++ obstack_grow (&dont_print_statmem_obstack, (char *) &addr, + sizeof (CORE_ADDR)); + + CHECK_TYPEDEF (type); + cp_print_value_fields (type, type, value_contents_all (val), +- value_embedded_offset (val), VALUE_ADDRESS (val), ++ value_embedded_offset (val), value_address (val), + stream, recurse, options, NULL, 1); + return; + } +@@ -492,7 +494,7 @@ cp_print_static_field (struct type *type, + opts = *options; + opts.deref_ref = 0; + val_print (type, value_contents_all (val), +- value_embedded_offset (val), VALUE_ADDRESS (val), ++ value_embedded_offset (val), value_address (val), + stream, recurse, &opts, current_language); + } + +diff --git a/gdb/dbxread.c b/gdb/dbxread.c +index 115bdef..7f756af 100644 +--- a/gdb/dbxread.c ++++ b/gdb/dbxread.c +@@ -1,6 +1,6 @@ + /* Read dbx symbol tables and convert to internal format, for GDB. + Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, +- 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2008. ++ 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2008, 2009. + Free Software Foundation, Inc. + + This file is part of GDB. +@@ -1188,6 +1188,8 @@ read_dbx_symtab (struct objfile *objfile) + struct internal_nlist nlist; + CORE_ADDR text_addr; + int text_size; ++ char *sym_name; ++ int sym_len; + + char *namestring; + int nsl; +@@ -1681,6 +1683,28 @@ pos %d"), + if (!p) + continue; /* Not a debugging symbol. */ + ++ sym_len = 0; ++ if (psymtab_language == language_cplus) ++ { ++ char *new_name, *name = alloca (p - namestring + 1); ++ memcpy (name, namestring, p - namestring); ++ name[p - namestring] = '\0'; ++ new_name = cp_canonicalize_string (name); ++ if (new_name != NULL) ++ { ++ sym_len = strlen (new_name); ++ sym_name = obsavestring (new_name, sym_len, ++ &objfile->objfile_obstack); ++ xfree (new_name); ++ } ++ } ++ ++ if (sym_len == 0) ++ { ++ sym_name = namestring; ++ sym_len = p - namestring; ++ } ++ + /* Main processing section for debugging symbols which + the initial read through the symbol tables needs to worry + about. If we reach this point, the symbol which we are +@@ -1698,7 +1722,7 @@ pos %d"), + namestring = gdbarch_static_transform_name (gdbarch, + namestring); + +- add_psymbol_to_list (namestring, p - namestring, ++ add_psymbol_to_list (sym_name, sym_len, + VAR_DOMAIN, LOC_STATIC, + &objfile->static_psymbols, + 0, nlist.n_value, +@@ -1710,7 +1734,7 @@ pos %d"), + data_sect_index); + /* The addresses in these entries are reported to be + wrong. See the code that reads 'G's for symtabs. */ +- add_psymbol_to_list (namestring, p - namestring, ++ add_psymbol_to_list (sym_name, sym_len, + VAR_DOMAIN, LOC_STATIC, + &objfile->global_psymbols, + 0, nlist.n_value, +@@ -1728,7 +1752,7 @@ pos %d"), + || (p == namestring + 1 + && namestring[0] != ' ')) + { +- add_psymbol_to_list (namestring, p - namestring, ++ add_psymbol_to_list (sym_name, sym_len, + STRUCT_DOMAIN, LOC_TYPEDEF, + &objfile->static_psymbols, + nlist.n_value, 0, +@@ -1736,7 +1760,7 @@ pos %d"), + if (p[2] == 't') + { + /* Also a typedef with the same name. */ +- add_psymbol_to_list (namestring, p - namestring, ++ add_psymbol_to_list (sym_name, sym_len, + VAR_DOMAIN, LOC_TYPEDEF, + &objfile->static_psymbols, + nlist.n_value, 0, +@@ -1749,7 +1773,7 @@ pos %d"), + case 't': + if (p != namestring) /* a name is there, not just :T... */ + { +- add_psymbol_to_list (namestring, p - namestring, ++ add_psymbol_to_list (sym_name, sym_len, + VAR_DOMAIN, LOC_TYPEDEF, + &objfile->static_psymbols, + nlist.n_value, 0, +@@ -1829,7 +1853,7 @@ pos %d"), + + case 'c': + /* Constant, e.g. from "const" in Pascal. */ +- add_psymbol_to_list (namestring, p - namestring, ++ add_psymbol_to_list (sym_name, sym_len, + VAR_DOMAIN, LOC_CONST, + &objfile->static_psymbols, nlist.n_value, + 0, psymtab_language, objfile); +@@ -1893,7 +1917,7 @@ pos %d"), + pst->textlow = nlist.n_value; + textlow_not_set = 0; + } +- add_psymbol_to_list (namestring, p - namestring, ++ add_psymbol_to_list (sym_name, sym_len, + VAR_DOMAIN, LOC_BLOCK, + &objfile->static_psymbols, + 0, nlist.n_value, +@@ -1961,7 +1985,7 @@ pos %d"), + pst->textlow = nlist.n_value; + textlow_not_set = 0; + } +- add_psymbol_to_list (namestring, p - namestring, ++ add_psymbol_to_list (sym_name, sym_len, + VAR_DOMAIN, LOC_BLOCK, + &objfile->global_psymbols, + 0, nlist.n_value, +@@ -3547,6 +3571,7 @@ static struct sym_fns aout_sym_fns = + dbx_new_init, /* sym_new_init: init anything gbl to entire symtab */ + dbx_symfile_init, /* sym_init: read initial info, setup for sym_read() */ + dbx_symfile_read, /* sym_read: read a symbol file into symtab */ ++ NULL, /* sym_read_psymbols */ + dbx_symfile_finish, /* sym_finish: finished with file, cleanup */ + default_symfile_offsets, /* sym_offsets: parse user's offsets to + internal form */ +diff --git a/gdb/defs.h b/gdb/defs.h +index 845b320..ad6e7d7 100644 +--- a/gdb/defs.h ++++ b/gdb/defs.h +@@ -151,6 +151,9 @@ extern int dbx_commands; + /* System root path, used to find libraries etc. */ + extern char *gdb_sysroot; + ++/* GDB datadir, used to store data files. */ ++extern char *gdb_datadir; ++ + /* Search path for separate debug files. */ + extern char *debug_file_directory; + +@@ -366,6 +369,9 @@ extern struct cleanup *make_cleanup_fclose (FILE *file); + + extern struct cleanup *make_cleanup_bfd_close (bfd *abfd); + ++struct obstack; ++extern struct cleanup *make_cleanup_obstack_free (struct obstack *obstack); ++ + extern struct cleanup *make_cleanup_restore_integer (int *variable); + + extern struct cleanup *make_final_cleanup (make_cleanup_ftype *, void *); +diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo +index 10e7388..d2c0f1e 100644 +--- a/gdb/doc/gdb.texinfo ++++ b/gdb/doc/gdb.texinfo +@@ -955,8 +955,10 @@ Connect to process ID @var{number}, as with the @code{attach} command. + @itemx -x @var{file} + @cindex @code{--command} + @cindex @code{-x} +-Execute @value{GDBN} commands from file @var{file}. @xref{Command +-Files,, Command files}. ++Execute commands from file @var{file}. If @var{file} ends in ++@samp{.py}, then the file is evaluated as Python code. If Python ++support is not enabled in this @value{GDBN}, then an error occurs. ++@xref{Command Files,, Command files}. + + @item -eval-command @var{command} + @itemx -ex @var{command} +@@ -1148,6 +1150,16 @@ for remote debugging. + Run using @var{device} for your program's standard input and output. + @c FIXME: kingdon thinks there is more to -tty. Investigate. + ++@item -P ++@cindex @code{-P} ++@itemx --python ++@cindex @code{--python} ++Change interpretation of command line so that the argument immediately ++following this switch is taken to be the name of a Python script file. ++This option stops option processing; subsequent options are passed to ++Python as @code{sys.argv}. This option is only available if Python ++scripting support was enabled when @value{GDBN} was configured. ++ + @c resolve the situation of these eventually + @item -tui + @cindex @code{--tui} +@@ -3636,6 +3648,98 @@ A failed Ada assertion. + A call to @code{exec}. This is currently only available for HP-UX + and @sc{gnu}/Linux. + ++@item syscall ++@itemx syscall @r{[}@var{name} @r{|} @var{number}@r{]} @r{...} ++@cindex break on a system call. ++A call to or return from a @code{syscall}. If no argument is specified, ++then it catches a call to or return from any system call. ++ ++@var{name} can be any valid system call name in the system. You can ++use the @value{GDBN} command-line completion facilities to list the ++available choices. @xref{Completion,, Command Completion}, for ++details on how to do this. ++ ++You may also specify the system call numerically. This may be useful ++if @value{GDBN} does not fully support your system's list of system ++calls. ++ ++The example below illustrates how this command works if you don't provide ++arguments to it: ++ ++@smallexample ++(@value{GDBP}) catch syscall ++Catchpoint 1 (syscall) ++(@value{GDBP}) r ++Starting program: /tmp/catch-syscall ++ ++Catchpoint 1 (call to syscall 'close'), 0xffffe424 in __kernel_vsyscall () ++(@value{GDBP}) c ++Continuing. ++ ++Catchpoint 1 (returned from syscall 'close'), 0xffffe424 in __kernel_vsyscall () ++(@value{GDBP}) ++@end smallexample ++ ++Here is an example of catching a system call by name: ++ ++@smallexample ++(@value{GDBP}) catch syscall chroot ++Catchpoint 1 (syscall(s) 'chroot') ++(@value{GDBP}) r ++Starting program: /tmp/catch-syscall ++ ++Catchpoint 1 (call to syscall 'chroot'), 0xffffe424 in __kernel_vsyscall () ++(@value{GDBP}) c ++Continuing. ++ ++Catchpoint 1 (returned from syscall 'chroot'), 0xffffe424 in __kernel_vsyscall () ++(@value{GDBP}) ++@end smallexample ++ ++And last but not least, an example of specifying a system call ++numerically: ++ ++@smallexample ++(@value{GDBP}) catch syscall 252 ++Catchpoint 1 (syscall(s) 'exit_group') ++(@value{GDBP}) r ++Starting program: /tmp/catch-syscall ++ ++Catchpoint 1 (call to syscall 'exit_group'), 0xffffe424 in __kernel_vsyscall () ++(@value{GDBP}) c ++Continuing. ++ ++Program exited normally. ++(@value{GDBP}) ++@end smallexample ++ ++If you configure @value{GDBN} using the @samp{--without-expat} option, ++it will not be able to display syscall names. Also, if your ++architecture does not have an XML file describing its system calls, ++you will not be able to see the syscall names. In either case, you ++will see a warning like this: ++ ++@smallexample ++(@value{GDBP}) catch syscall ++warning: Could not open "syscalls/i386-linux.xml" ++warning: Could not load the syscall XML file 'syscalls/i386-linux.xml'. ++GDB will not be able to display syscall names. ++Catchpoint 1 (syscall) ++(@value{GDBP}) ++@end smallexample ++ ++Of course, the file name will change depending on your architecture and system. ++ ++Still using the example above, you can also try to catch a syscall by its ++number. In this case, you would see something like: ++ ++@smallexample ++(@value{GDBP}) catch syscall 252 ++Catchpoint 1 (syscall(s) 252) ++@end smallexample ++ ++Again, in this case @value{GDBN} would not be able to display syscall's names. ++ + @item fork + A call to @code{fork}. This is currently only available for HP-UX + and @sc{gnu}/Linux. +@@ -4711,6 +4815,24 @@ the program to report that some thread has stopped before prompting for + another command. In background execution, @value{GDBN} immediately gives + a command prompt so that you can issue other commands while your program runs. + ++You need to explicitly enable asynchronous mode before you can use ++background execution commands. You can use these commands to ++manipulate the asynchronous mode setting: ++ ++@table @code ++@kindex set target-async ++@item set target-async on ++Enable asynchronous mode. ++@item set target-async off ++Disable asynchronous mode. ++@kindex show target-async ++@item show target-async ++Show the current target-async setting. ++@end table ++ ++If the target doesn't support async mode, @value{GDBN} issues an error ++message if you attempt to use the background execution commands. ++ + To specify background execution, add a @code{&} to the command. For example, + the background form of the @code{continue} command is @code{continue&}, or + just @code{c&}. The execution commands that accept background execution +@@ -4776,11 +4898,6 @@ only the current thread. To stop the whole program in non-stop mode, + use @code{interrupt -a}. + @end table + +-You may need to explicitly enable async mode before you can use background +-execution commands, with the @code{set target-async 1} command. If the +-target doesn't support async mode, @value{GDBN} issues an error message +-if you attempt to use the background execution commands. +- + @node Thread-Specific Breakpoints + @subsection Thread-Specific Breakpoints + +@@ -6536,6 +6653,12 @@ Without this format, @value{GDBN} displays pointers to and arrays of + @code{char}, @w{@code{unsigned char}}, and @w{@code{signed char}} as + strings. Single-byte members of a vector are displayed as an integer + array. ++ ++@item r ++@cindex raw printing ++Print using the @samp{raw} formatting. By default, @value{GDBN} will ++use a type-specific pretty-printer. The @samp{r} format bypasses any ++pretty-printer which might exist for the value's type. + @end table + + For example, to print the program counter in hex (@pxref{Registers}), type +@@ -7408,6 +7531,20 @@ On HP-UX systems, if you refer to a function or variable name that + begins with a dollar sign, @value{GDBN} searches for a user or system + name first, before it searches for a convenience variable. + ++@cindex convenience functions ++@value{GDBN} also supplies some @dfn{convenience functions}. These ++have a syntax similar to convenience variables. A convenience ++function can be used in an expression just like an ordinary function; ++however, a convenience function is implemented internally to ++@value{GDBN}. ++ ++@table @code ++@item help function ++@kindex help function ++@cindex show all convenience functions ++Print a list of all convenience functions. ++@end table ++ + @node Registers + @section Registers + +@@ -7931,13 +8068,17 @@ support: + @table @code + @item set target-charset @var{charset} + @kindex set target-charset +-Set the current target character set to @var{charset}. We list the +-character set names @value{GDBN} recognizes below, but if you type +-@code{set target-charset} followed by @key{TAB}@key{TAB}, @value{GDBN} will +-list the target character sets it supports. +-@end table ++Set the current target character set to @var{charset}. If you type ++@code{set target-charset} followed by @key{TAB}@key{TAB}, @value{GDBN} ++will list the target character sets it supports. ++ ++@item set target-wide-charset @var{charset} ++@kindex set target-wide-charset ++Set the current target wide character set to @var{charset}. The ++target wide character set is the character set used by @code{wchar_t}. ++If you type @code{set target-charset} followed by @key{TAB}@key{TAB}, ++@value{GDBN} will list the target character sets it supports. + +-@table @code + @item set host-charset @var{charset} + @kindex set host-charset + Set the current host character set to @var{charset}. +@@ -7947,10 +8088,9 @@ system it is running on; you can override that default using the + @code{set host-charset} command. + + @value{GDBN} can only use certain character sets as its host character +-set. We list the character set names @value{GDBN} recognizes below, and +-indicate which can be host character sets, but if you type +-@code{set target-charset} followed by @key{TAB}@key{TAB}, @value{GDBN} will +-list the host character sets it supports. ++set. If you type @code{set target-charset} followed by ++@key{TAB}@key{TAB}, @value{GDBN} will list the host character sets it ++supports. + + @item set charset @var{charset} + @kindex set charset +@@ -7974,37 +8114,6 @@ Show the name of the current target charset. + + @end table + +-@value{GDBN} currently includes support for the following character +-sets: +- +-@table @code +- +-@item ASCII +-@cindex ASCII character set +-Seven-bit U.S. @sc{ascii}. @value{GDBN} can use this as its host +-character set. +- +-@item ISO-8859-1 +-@cindex ISO 8859-1 character set +-@cindex ISO Latin 1 character set +-The ISO Latin 1 character set. This extends @sc{ascii} with accented +-characters needed for French, German, and Spanish. @value{GDBN} can use +-this as its host character set. +- +-@item EBCDIC-US +-@itemx IBM1047 +-@cindex EBCDIC character set +-@cindex IBM1047 character set +-Variants of the @sc{ebcdic} character set, used on some of IBM's +-mainframe operating systems. (@sc{gnu}/Linux on the S/390 uses U.S. @sc{ascii}.) +-@value{GDBN} cannot use these as its host character set. +- +-@end table +- +-Note that these are all single-byte character sets. More work inside +-@value{GDBN} is needed to support multi-byte or variable-width character +-encodings, like the UTF-8 and UCS-2 encodings of Unicode. +- + Here is an example of @value{GDBN}'s character set support in action. + Assume that the following source code has been placed in the file + @file{charset-test.c}: +@@ -12510,6 +12619,12 @@ It is possible for the function you call via the @code{print} or + the function, or if you passed it incorrect arguments). What happens + in that case is controlled by the @code{set unwindonsignal} command. + ++Similarly, with a C++ program it is possible for the function you ++call via the @code{print} or @code{call} command to generate an ++exception that is not handled due to the constraints of the dummy ++frame. What happens in that case is controlled by the ++@code{set unwind-on-terminating-exception} command. ++ + @table @code + @item set unwindonsignal + @kindex set unwindonsignal +@@ -12526,6 +12641,23 @@ received. + @kindex show unwindonsignal + Show the current setting of stack unwinding in the functions called by + @value{GDBN}. ++ ++@item set unwind-on-terminating-exception ++@kindex set unwind-on-terminating-exception ++@cindex unwind stack in called functions ++@cindex call dummy stack unwinding on unhandled exception. ++Set unwinding of the stack if a C++ exception is raised but unhandled ++while in a function that @value{GDBN} called in the program being ++debugged. If set to on (the default), @value{GDBN} unwinds the stack ++it created for the call and restores the context to what it was before ++the call. If set to off, @value{GDBN} the exception is delivered to ++the default C++ exception handler. ++ ++@item show unwind-on-terminating-exception ++@kindex show unwind-on-terminating-exception ++Show the current setting of stack unwinding in the functions called by ++@value{GDBN}. ++ + @end table + + @cindex weak alias functions +@@ -17815,7 +17947,7 @@ command: + @table @code + @kindex source + @cindex execute commands from a file +-@item source [@code{-v}] @var{filename} ++@item source [@code{-v}] [@code{-p}] @var{filename} + Execute the command file @var{filename}. + @end table + +@@ -17832,6 +17964,11 @@ If @code{-v}, for verbose mode, is given then @value{GDBN} displays + each command as it is executed. The option must be given before + @var{filename}, and is interpreted as part of the filename anywhere else. + ++If @var{filename} ends in @samp{.py}, or if @code{-p}, for Python, is ++given then @value{GDBN} evaluates the contents of the file as Python ++code. If Python support is not compiled in to @value{GDBN}, then an ++error occurs. ++ + Commands that would ask for confirmation if used interactively proceed + without asking when used in a command file. Many @value{GDBN} commands that + normally print messages to say what they are doing omit the messages +@@ -18093,8 +18230,6 @@ containing @code{end}. For example: + + @smallexample + (@value{GDBP}) python +-Type python script +-End with a line saying just "end". + >print 23 + >end + 23 +@@ -18107,6 +18242,14 @@ in a Python script. This can be controlled using @code{maint set + python print-stack}: if @code{on}, the default, then Python stack + printing is enabled; if @code{off}, then Python stack printing is + disabled. ++ ++@kindex maint set python auto-load ++@item maint set python auto-load ++By default, @value{GDBN} will attempt to automatically load Python ++code when an object file is opened. This can be controlled using ++@code{maint set python auto-load}: if @code{on}, the default, then ++Python auto-loading is enabled; if @code{off}, then Python ++auto-loading is disabled. + @end table + + @node Python API +@@ -18114,6 +18257,14 @@ disabled. + @cindex python api + @cindex programming in python + ++You can get quick online help for @value{GDBN}'s Python API by issuing ++the command @w{@kbd{python help (gdb)}}. ++ ++Functions and methods which have two or more optional arguments allow ++them to be specified using keyword syntax. This allows passing some ++optional arguments while skipping others. Example: ++@w{@code{gdb.some_function ('foo', bar = 1, baz = 2)}}. ++ + @cindex python stdout + @cindex python pagination + At startup, @value{GDBN} overrides Python's @code{sys.stdout} and +@@ -18125,8 +18276,17 @@ situation, a Python @code{KeyboardInterrupt} exception is thrown. + @menu + * Basic Python:: Basic Python Functions. + * Exception Handling:: +-* Values From Inferior:: ++* Auto-loading:: Automatically loading Python code. ++* Values From Inferior:: Python representation of values. ++* Types From Inferior:: Python representation of types. ++* Pretty Printing:: Pretty-printing values. ++* Threads In Python:: Accessing inferior threads from Python. + * Commands In Python:: Implementing new commands in Python. ++* Parameters In Python:: Adding new @value{GDBN} parameters. ++* Functions In Python:: Writing new convenience functions. ++* Objfiles In Python:: Object files. ++* Breakpoints In Python:: Manipulating breakpoints using Python. ++* Frames In Python:: Acessing inferior stack frames from Python. + @end menu + + @node Basic Python +@@ -18152,10 +18312,30 @@ command as having originated from the user invoking it interactively. + It must be a boolean value. If omitted, it defaults to @code{False}. + @end defun + +-@findex gdb.get_parameter +-@defun get_parameter parameter +-Return the value of a @value{GDBN} parameter. @var{parameter} is a +-string naming the parameter to look up; @var{parameter} may contain ++@findex gdb.current_objfile ++@defun current_objfile ++When auto-loading a Python script (@pxref{Auto-loading}), @value{GDBN} ++sets the ``current objfile'' to the corresponding objfile. This ++function returns the current objfile. If there is no current objfile, ++this function returns @code{None}. ++@end defun ++ ++@findex gdb.breakpoints ++@defun breakpoints ++Return a sequence holding all of @value{GDBN}'s breakpoints. ++@xref{Breakpoints In Python}, for more information. ++@end defun ++ ++@findex gdb.objfiles ++@defun objfiles ++Return a sequence of all the objfiles current known to @value{GDBN}. ++@xref{Objfiles In Python}. ++@end defun ++ ++@findex gdb.parameter ++@defun parameter name ++Return the value of the named @value{GDBN} parameter. @var{name} is a ++string naming the parameter to look up; @var{name} may contain + spaces if the parameter has a multi-part name. For example, + @samp{print object} is a valid parameter name. + +@@ -18179,6 +18359,28 @@ If no exception is raised, the return value is always an instance of + @code{gdb.Value} (@pxref{Values From Inferior}). + @end defun + ++@findex gdb.parse_and_eval ++@defun parse_and_eval expression ++Parse @var{expression} as an expression in the current language, ++evaluate it, and return the result as a @code{gdb.Value}. ++@var{expression} must be a string. ++@end defun ++ ++@findex gdb.post_event ++@defun post_event event ++Put @var{event}, a callable object taking no arguments, into ++@value{GDBN}'s internal event queue. This callable will be invoked at ++some later point, during @value{GDBN}'s event processing. Events ++posted using @code{post_event} will be run in the order in which they ++were posted; however, there is no way to know when they will be ++processed relative to other events inside @value{GDBN}. ++ ++@value{GDBN} is not thread-safe. If your Python program uses multiple ++threads, you must be careful to only call @value{GDBN}-specific ++functions in the main @value{GDBN} thread. @code{post_event} ensures ++this. ++@end defun ++ + @findex gdb.write + @defun write string + Print a string to @value{GDBN}'s paginated standard output stream. +@@ -18193,6 +18395,66 @@ Flush @value{GDBN}'s paginated standard output stream. Flushing + function. + @end defun + ++@findex gdb.frames ++@defun frames ++Return a tuple of all frame objects. ++@end defun ++ ++@findex gdb.newest_frame ++@defun newest_frame ++Return the newest frame object. ++@end defun ++ ++@findex gdb.selected_frame ++@defun selected_frame ++Return the selected frame object. ++@end defun ++ ++@findex gdb.frame_stop_reason_string ++@defun frame_stop_reason_string @var{reason} ++Return a string explaining the reason why @value{GDBN} stopped unwinding ++frames, as expressed by the given @var{reason} code (an integer, see the ++@code{unwind_stop_reason} method in ++@xref{Frames In Python,,Accessing inferior stack frames from Python}.) ++@end defun ++ ++@findex gdb.read_memory ++@defun read_memory @var{address} @var{length} ++Read @var{length} bytes of memory from the inferior, starting at @var{address}. ++Returns a buffer object, which behaves much like an array or a string. It ++can be modified and given to the @code{gdb.write_memory} function. ++@end defun ++ ++@findex gdb.write_memory ++@defun write_memory @var{address} @var{buffer} @r{[}@var{length}@r{]} ++Write the contents of @var{buffer} (a Python object which supports the buffer ++protocol, i.e., a string, an array or the object returned from ++@code{gdb.read_memory}) to the inferior, starting at @var{address}. If given, ++@var{length} determines the number of bytes from @var{buffer} to be written. ++@end defun ++ ++@findex gdb.search_memory ++@defun search_memory @var{address} @var{length} @var{pattern} @r{[}@var{size}@r{]} @r{[}@var{max_count}@r{]} ++Search a region of the inferior memory starting at @var{address} with the given ++@var{length}. @var{pattern} can be a string, a byte array, a buffer object, ++a number, a @code{gdb.Value} object (@pxref{Values From Inferior}) or a list ++or tuple with elements in any combination of those types. If @var{size} is ++given and is non-zero, it specifies the size in bytes of a Python scalar or ++@code{gdb.Value} in the search pattern. If @var{size} is zero or not specified, ++ it is taken from the value's type in the current language. ++This is useful when one wants to specify the search ++pattern as a mixture of types. ++Note that this means, for example, that in the case of C-like languages ++a search for an untyped 0x42 will search for @samp{(int) 0x42} ++which is typically four bytes. @var{max_count} is the highest number of matches ++to search for. ++@end defun ++ ++@findex gdb.solib_address ++@defun solib_address @var{address} ++Return the name of the shared library holding the given address, or None. ++@end defun ++ + @node Exception Handling + @subsubsection Exception Handling + @cindex python exceptions +@@ -18224,6 +18486,44 @@ message as its value, and the Python call stack backtrace at the + Python statement closest to where the @value{GDBN} error occured as the + traceback. + ++@node Auto-loading ++@subsubsection Auto-loading ++ ++When a new object file (@pxref{Objfiles In Python}) is read (for ++example, due to the @code{file} command, or because the inferior has ++loaded a shared library), @value{GDBN} will look for a file named by ++adding @samp{-gdb.py} to the object file's real name (the name formed ++after following all symlinks and resolving @code{.} and @code{..} ++components). If this file exists and is readable, @value{GDBN} will ++evaluate it as a Python script. ++ ++If this file does not exist, and if the parameter ++@code{debug-file-directory} is set, then @value{GDBN} will append the ++object file's real name to the value of this parameter, and try again. ++ ++Finally, if this file does not exist, then @value{GDBN} will look in ++subdirectory of @code{gdb_datadir} (whose value is available from ++@code{maint show gdb_datadir}). Specifically, @value{GDBN} will take ++the value of @code{gdb_datadir}, append @samp{python/auto-load}, and ++then append the object file's real name. ++ ++Also, if a separate debug file is used, @value{GDBN} will look for the ++@samp{-gdb.py} file both in the directory associated with the ++application and the directory associated with the separate debug file. ++ ++When reading a @samp{-gdb.py} file, @value{GDBN} sets the ``current ++objfile''. This is available via the @code{gdb.current_objfile} ++function. This can be useful for registering objfile-specific ++pretty-printers. ++ ++This feature is useful for supplying application-specific debugging ++commands and scripts. It can be disabled using @code{maint set python ++auto-load}. ++ ++@value{GDBN} does not track which files it has already auto-loaded. ++So, your @samp{-gdb.py} file should take care to ensure that it may be ++evaluated multiple times without error. ++ + @node Values From Inferior + @subsubsection Values From Inferior + @cindex values from inferior, with Python +@@ -18258,8 +18558,21 @@ bar = some_val['foo'] + + Again, @code{bar} will also be a @code{gdb.Value} object. + +-For pointer data types, @code{gdb.Value} provides a method for +-dereferencing the pointer to obtain the object it points to. ++The following methods are provided: ++ ++@table @code ++@defmethod Value address ++If the @code{gdb.Value} object is addressable, this will return a new ++@code{gdb.Value} object representing the address. Otherwise, this ++will throw an exception. ++@end defmethod ++ ++@defmethod Value cast type ++Cast the @code{gdb.Value} to the type represented by @var{type}, and ++return a new @code{gdb.Value}. @var{type} must be a @code{gdb.Type} ++object. If the cast cannot be performed for some reason, an exception ++is thrown. ++@end defmethod + + @defmethod Value dereference + This method returns a new @code{gdb.Value} object whose contents is +@@ -18282,7 +18595,7 @@ The result @code{bar} will be a @code{gdb.Value} object holding the + value pointed to by @code{foo}. + @end defmethod + +-@defmethod Value string @r{[}encoding @r{[}errors@r{]}@r{]} ++@defmethod Value string @r{[}encoding@r{]} @r{[}errors@r{]} + If this @code{gdb.Value} represents a string, then this method + converts the contents to a Python string. Otherwise, this method will + throw an exception. +@@ -18309,6 +18622,468 @@ The optional @var{errors} argument is the same as the corresponding + argument to Python's @code{string.decode} method. + @end defmethod + ++@defmethod Value type ++Return the type of this @code{gdb.Value}. The result is a ++@code{gdb.Type} object. ++@end defmethod ++@end table ++ ++@node Types From Inferior ++@subsubsection Types From Inferior ++ ++@cindex gdb.Type ++@value{GDBN} represents types from the inferior using the class ++@code{gdb.Type}. ++ ++The following methods are provided: ++ ++@table @code ++@defmethod Type Type [name [block]] ++Construct a new instance of @code{gdb.Type}. ++ ++If @var{name} is given, it specifies the name of a type to look up in ++the inferior. ++ ++If @var{block} is given, then @var{name} is looked up in that scope. ++Otherwise, it is searched for globally. ++@end defmethod ++ ++@defmethod Type code ++Return the type code for this type. The type code will be one of the ++@code{TYPE_CODE_} constants defined below. ++@end defmethod ++ ++@defmethod Type fields ++For structure and union types, this method returns the fields. Range ++types have two fields, the minimum and maximum values. Enum types ++have one field per enum constant. Function and method types have one ++field per parameter. The base types of C++ classes are also ++represented as fields. If the type has no fields, or does not fit ++into one of these categories, an empty sequence will be returned. ++ ++Each field is an object, with some pre-defined attributes: ++@table @code ++@item bitpos ++This attribute is not available for @code{static} fields. For ++non-@code{static} fields, the value is the bit position of the field. ++ ++@item name ++The name of the field, or @code{None} for anonymous fields. ++ ++@item artificial ++This is @code{True} if the field is artificial, usually meaning that ++it was provided by the compiler and not the user. This attribute is ++always provided, and is @code{False} if the field is not artificial. ++ ++@item bitsize ++If the field is packed, or is a bitfield, then this will have a ++non-zero value, which is the size of the field in bits. Otherwise, ++this will be zero; in this case the field's size is given by its type. ++ ++@item type ++The type of the field. ++@end table ++@end defmethod ++ ++@defmethod Type const ++Return a new @code{gdb.Type} object which represents a ++@code{const}-qualified variant of this type. ++@end defmethod ++ ++@defmethod Type volatile ++Return a new @code{gdb.Type} object which represents a ++@code{volatile}-qualified variant of this type. ++@end defmethod ++ ++@defmethod Type unqualified ++Return a new @code{gdb.Type} object which represents an unqualified ++variant of this type. That is, the result is neither @code{const} nor ++@code{volatile}. ++@end defmethod ++ ++@defmethod Type reference ++Return a new @code{gdb.Type} object which represents a reference to this ++type. ++@end defmethod ++ ++@defmethod Type sizeof ++Return the size of this type, in target @code{char} units. Usually, a ++target's @code{char} type will be an 8-bit byte. However, on some ++unusual platforms, this type may have a different size. ++@end defmethod ++ ++@defmethod Type strip_typedefs ++Return a new @code{gdb.Type} that represents the real type, ++after removing all layers of typedefs. ++@end defmethod ++ ++@defmethod Type tag ++Return the tag name for this type. The tag name is the name after ++@code{struct}, @code{union}, or @code{enum} in C; not all languages ++have this concept. If this type has no tag name, then @code{None} is ++returned. ++@end defmethod ++ ++@defmethod Type target ++Return a new @code{gdb.Type} object which represents the target type ++of this type. ++ ++For a pointer type, the target type is the type of the pointed-to ++object. For an array type, the target type is the type of the ++elements of the array. For a function type, the target type is the ++type of the return value. For a complex type, the target type is the ++type of the elements. For a typedef, the target type is the aliased ++type. ++@end defmethod ++ ++@defmethod Type template_argument n [block] ++If this @code{gdb.Type} is a template type, this will return a new ++@code{gdb.Type} which represents the type of the @var{n}th template ++argument. ++ ++If this @code{gdb.Type} is not a template type, this will throw an ++exception. ++ ++If @var{block} is given, then @var{name} is looked up in that scope. ++Otherwise, it is searched for globally. ++@end defmethod ++@end table ++ ++ ++Each type has a code, which indicates what category this type falls ++into. The available type categories are represented by constants ++defined in the @code{gdb} module: ++ ++@table @code ++@findex TYPE_CODE_PTR ++@findex gdb.TYPE_CODE_PTR ++@item TYPE_CODE_PTR ++The type is a pointer. ++ ++@findex TYPE_CODE_ARRAY ++@findex gdb.TYPE_CODE_ARRAY ++@item TYPE_CODE_ARRAY ++The type is an array. ++ ++@findex TYPE_CODE_STRUCT ++@findex gdb.TYPE_CODE_STRUCT ++@item TYPE_CODE_STRUCT ++The type is a structure. ++ ++@findex TYPE_CODE_UNION ++@findex gdb.TYPE_CODE_UNION ++@item TYPE_CODE_UNION ++The type is a union. ++ ++@findex TYPE_CODE_ENUM ++@findex gdb.TYPE_CODE_ENUM ++@item TYPE_CODE_ENUM ++The type is an enum. ++ ++@findex TYPE_CODE_FLAGS ++@findex gdb.TYPE_CODE_FLAGS ++@item TYPE_CODE_FLAGS ++A bit flags type. ++@c FIXME: what is this? ++ ++@findex TYPE_CODE_FUNC ++@findex gdb.TYPE_CODE_FUNC ++@item TYPE_CODE_FUNC ++The type is a function. ++ ++@findex TYPE_CODE_INT ++@findex gdb.TYPE_CODE_INT ++@item TYPE_CODE_INT ++The type is an integer type. ++ ++@findex TYPE_CODE_FLT ++@findex gdb.TYPE_CODE_FLT ++@item TYPE_CODE_FLT ++A floating point type. ++ ++@findex TYPE_CODE_VOID ++@findex gdb.TYPE_CODE_VOID ++@item TYPE_CODE_VOID ++The special type @code{void}. ++ ++@findex TYPE_CODE_SET ++@findex gdb.TYPE_CODE_SET ++@item TYPE_CODE_SET ++A Pascal set type. ++ ++@findex TYPE_CODE_RANGE ++@findex gdb.TYPE_CODE_RANGE ++@item TYPE_CODE_RANGE ++A range type, that is, an integer type with bounds. ++ ++@findex TYPE_CODE_STRING ++@findex gdb.TYPE_CODE_STRING ++@item TYPE_CODE_STRING ++A string type. Note that this is only used for certain languages with ++language-defined string types; C strings are not represented this way. ++ ++@findex TYPE_CODE_BITSTRING ++@findex gdb.TYPE_CODE_BITSTRING ++@item TYPE_CODE_BITSTRING ++A string of bits. ++ ++@findex TYPE_CODE_ERROR ++@findex gdb.TYPE_CODE_ERROR ++@item TYPE_CODE_ERROR ++An unknown or erroneous type. ++ ++@findex TYPE_CODE_METHOD ++@findex gdb.TYPE_CODE_METHOD ++@item TYPE_CODE_METHOD ++A C++ method type. ++ ++@findex TYPE_CODE_METHODPTR ++@findex gdb.TYPE_CODE_METHODPTR ++@item TYPE_CODE_METHODPTR ++A pointer-to-member-function. ++ ++@findex TYPE_CODE_MEMBERPTR ++@findex gdb.TYPE_CODE_MEMBERPTR ++@item TYPE_CODE_MEMBERPTR ++A pointer-to-member. ++ ++@findex TYPE_CODE_REF ++@findex gdb.TYPE_CODE_REF ++@item TYPE_CODE_REF ++A reference type. ++ ++@findex TYPE_CODE_CHAR ++@findex gdb.TYPE_CODE_CHAR ++@item TYPE_CODE_CHAR ++A character type. ++ ++@findex TYPE_CODE_BOOL ++@findex gdb.TYPE_CODE_BOOL ++@item TYPE_CODE_BOOL ++A boolean type. ++ ++@findex TYPE_CODE_COMPLEX ++@findex gdb.TYPE_CODE_COMPLEX ++@item TYPE_CODE_COMPLEX ++A complex float type. ++ ++@findex TYPE_CODE_TYPEDEF ++@findex gdb.TYPE_CODE_TYPEDEF ++@item TYPE_CODE_TYPEDEF ++A typedef to some other type. ++ ++@findex TYPE_CODE_TEMPLATE ++@findex gdb.TYPE_CODE_TEMPLATE ++@item TYPE_CODE_TEMPLATE ++A C++ template type. Note that this is not used for a template ++instantiation; those appear as ordinary struct types. ++@c FIXME I hope that is true ++ ++@findex TYPE_CODE_TEMPLATE_ARG ++@findex gdb.TYPE_CODE_TEMPLATE_ARG ++@item TYPE_CODE_TEMPLATE_ARG ++A C++ template argument. ++@c FIXME: is this ever used? ++ ++@findex TYPE_CODE_NAMESPACE ++@findex gdb.TYPE_CODE_NAMESPACE ++@item TYPE_CODE_NAMESPACE ++A C++ namespace. ++ ++@findex TYPE_CODE_DECFLOAT ++@findex gdb.TYPE_CODE_DECFLOAT ++@item TYPE_CODE_DECFLOAT ++A decimal floating point type. ++ ++@findex TYPE_CODE_INTERNAL_FUNCTION ++@findex gdb.TYPE_CODE_INTERNAL_FUNCTION ++@item TYPE_CODE_INTERNAL_FUNCTION ++A function internal to @value{GDBN}. This is the type used to represent ++convenience functions. ++@end table ++ ++@node Pretty Printing ++@subsubsection Pretty Printing ++ ++@value{GDBN} provides a mechanism to allow pretty-printing of values ++using Python code. This mechanism works for both MI and the CLI. ++ ++A pretty-printer is an object that implements a specific interface. ++There is no predefined base class for pretty-printers. ++ ++@defop Operation {pretty printer} __init__ (self, val) ++When printing a value, @value{GDBN} constructs an instance of the ++pretty-printer. @var{val} is the value to be printed, an instance of ++@code{gdb.Value}. ++@end defop ++ ++@defop Operation {pretty printer} children (self) ++When printing a value, @value{GDBN} will call this method to compute ++the children of the value passed to the object's constructor. ++ ++This method must return an object conforming to the Python iterator ++protocol. Each element returned by the iterator must be a tuple ++holding two elements. The first element is the ``name'' of the child; ++the second element is the child's value. The value can be any Python ++object which is convertible to a @value{GDBN} value. ++ ++This method is optional. If it does not exist, @value{GDBN} will act ++as though the value has no children. ++@end defop ++ ++@defop Operation {pretty printer} display_hint (self) ++This method must return a string. The CLI may use this to change the ++formatting of children of a value. The result will also be supplied ++to an MI consumer as a @samp{displayhint} attribute of the variable ++being printed. ++ ++Some display hints are predefined by @value{GDBN}: ++ ++@table @samp ++@item array ++Indicate that the object being printed is ``array-like''. The CLI ++uses this to respect parameters such as @code{set print elements} and ++@code{set print array}. ++ ++@item map ++Indicate that the object being printed is ``map-like'', and that the ++children of this value can be assumed to alternate between keys and ++values. ++ ++@item string ++Indicate that the object being printed is ``string-like''. If the ++printer's @code{to_string} method returns a Python string of some ++kind, then @value{GDBN} will call its internal language-specific ++string-printing function to format the string. For the CLI this means ++adding quotation marks, possibly escaping some characters, respecting ++@code{set print elements}, and the like. ++@end table ++@end defop ++ ++@defop Operation {pretty printer} to_string (self) ++@value{GDBN} will call this method to display the string ++representation of the value passed to the object's constructor. ++ ++When printing from the CLI, if the @code{to_string} method exists, ++then @value{GDBN} will prepend its result to the values returned by ++@code{children}. ++ ++If this method returns a string, it is printed verbatim. Otherwise, ++the result is converted to a @code{gdb.Value}, following the usual ++algorithm. Then @value{GDBN} prints this value; this may possibly ++result in a call to another pretty-printer. If the result is not ++convertible to @code{gdb.Value}, an exception is raised. ++@end defop ++ ++@subsubsection Selecting Pretty-Printers ++ ++The Python list @code{gdb.pretty_printers} contains an array of ++functions that have been registered via addition as a pretty-printer. ++Each function will be called with a @code{gdb.Value} to be ++pretty-printed. Each @code{gdb.Objfile} also contains a ++@code{pretty_printers} attribute. A function on one of these lists ++takes a single @code{gdb.Value} argument and returns a pretty-printer ++object conforming to the interface definition above. If this function ++cannot create a pretty-printer for the value, it should return ++@code{None}. ++ ++@value{GDBN} first checks the @code{pretty_printers} attribute of each ++@code{gdb.Objfile} and iteratively calls each function in the list for ++that @code{gdb.Objfile} until it receives a pretty-printer object. ++After these @code{gdb.Objfile} have been exhausted, it tries the ++global @code{gdb.pretty-printers} list, again calling each function ++until an object is returned. ++ ++The order in which the objfiles are searched is not specified. ++Functions are always invoked from the head of the ++@code{gdb.pretty-printers} list, and iterated over sequentially until ++the end of the list, or a printer object is returned. ++ ++Here is an example showing how a @code{std::string} printer might be ++written: ++ ++@smallexample ++class StdStringPrinter: ++ "Print a std::string" ++ ++ def __init__ (self, val): ++ self.val = val ++ ++ def to_string (self): ++ return self.val['_M_dataplus']['_M_p'] ++@end smallexample ++ ++And here is an example showing how a lookup function for ++the printer example above might be written. ++ ++@smallexample ++def str_lookup_function (val): ++ ++ lookup_tag = val.type ().tag () ++ regex = re.compile ("^std::basic_string$") ++ if lookup_tag == None: ++ return None ++ if regex.match (lookup_tag): ++ return StdStringPrinter (val) ++ ++ return None ++@end smallexample ++ ++The example lookup function extracts the value's type, and attempts to ++match it to a type that it can pretty-print. If it is a type the ++printer can pretty-print, it will return a printer object. If not, it ++returns: @code{None}. ++ ++We recommend that you put your core pretty-printers into a versioned ++python package, and then restrict your auto-loaded code to idempotent ++behavior -- for example, just @code{import}s of your printer modules, ++followed by a call to a register pretty-printers with the current ++objfile. This approach will scale more nicely to multiple inferiors, ++potentially using different library versions. ++ ++For example, in addition to the above, this code might appear in ++@code{gdb.libstdcxx.v6}: ++ ++@smallexample ++def register_printers (objfile): ++ objfile.pretty_printers.add (str_lookup_function) ++@end smallexample ++ ++And then the corresponding contents of the auto-load file would be: ++ ++@smallexample ++import gdb.libstdcxx.v6 ++gdb.libstdcxx.v6.register_printers (gdb.current_objfile ()) ++@end smallexample ++ ++@node Threads In Python ++@subsubsection Threads In Python ++ ++Python scripts can access information about the inferior's threads ++using some functions provided by @value{GDBN}. Like all of ++@value{GDBN}'s Python additions, these are in the @code{gdb} module: ++ ++@findex gdb.threads ++@defun threads ++This function returns a tuple holding all the thread IDs which are ++valid when the function is called. If there are no valid threads, ++this will return @code{None}. ++@end defun ++ ++@findex gdb.current_thread ++@defun current_thread ++This function returns the thread ID of the selected thread. If there ++is no selected thread, this will return @code{None}. ++@end defun ++ ++@findex gdb.switch_to_thread ++@defun switch_to_thread id ++This changes @value{GDBN}'s currently selected thread to the thread ++given by @var{id}. @var{id} must be a valid thread ID as returned by ++@code{threads}. If @var{id} is invalid, this function throws an ++exception. ++@end defun ++ + @node Commands In Python + @subsubsection Commands In Python + +@@ -18320,7 +19095,7 @@ You can implement new @value{GDBN} CLI commands in Python. A CLI + command is implemented using an instance of the @code{gdb.Command} + class, most commonly using a subclass. + +-@defmethod Command __init__ name @var{command-class} @r{[}@var{completer-class} @var{prefix}@r{]} ++@defmethod Command __init__ name @var{command_class} @r{[}@var{completer_class}@r{]} @r{[}@var{prefix}@r{]} + The object initializer for @code{Command} registers the new command + with @value{GDBN}. This initializer is normally invoked from the + subclass' own @code{__init__} method. +@@ -18332,11 +19107,11 @@ an exception is raised. + + There is no support for multi-line commands. + +-@var{command-class} should be one of the @samp{COMMAND_} constants ++@var{command_class} should be one of the @samp{COMMAND_} constants + defined below. This argument tells @value{GDBN} how to categorize the + new command in the help system. + +-@var{completer-class} is an optional argument. If given, it should be ++@var{completer_class} is an optional argument. If given, it should be + one of the @samp{COMPLETE_} constants defined below. This argument + tells @value{GDBN} how to perform completion for this command. If not + given, @value{GDBN} will attempt to complete using the object's +@@ -18563,6 +19338,374 @@ registration of the command with @value{GDBN}. Depending on how the + Python code is read into @value{GDBN}, you may need to import the + @code{gdb} module explicitly. + ++ ++@node Parameters In Python ++@subsubsection Parameters In Python ++ ++@cindex parameters in python ++@cindex python parameters ++@tindex gdb.Parameter ++@tindex Parameter ++You can implement new @value{GDBN} parameters using Python. A new ++parameter is implemented as an instance of the @code{gdb.Parameter} ++class. Parameters are exposed to the user via the @code{set} and ++@code{show} commands. ++ ++@defmethod Parameter __init__ name @var{command-class} @var{parameter-class} @r{[}@var{enum-sequence}@r{]} ++The object initializer for @code{Parameter} registers the new ++parameter with @value{GDBN}. This initializer is normally invoked ++from the subclass' own @code{__init__} method. ++ ++@var{name} is the name of the new parameter. If @var{name} consists ++of multiple words, then the initial words are looked for as prefix ++commands. In this case, if one of the prefix commands does not exist, ++an exception is raised. ++ ++@var{command-class} should be one of the @samp{COMMAND_} constants ++(@pxref{Commands In Python}). This argument tells @value{GDBN} how to ++categorize the new parameter in the help system. ++ ++@var{parameter-class} should be one of the @samp{PARAM_} constants ++defined below. This argument tells @value{GDBN} the type of the new ++parameter; this information is used for input validation and ++completion. ++ ++If @var{parameter-class} is @code{PARAM_ENUM}, then ++@var{enum-sequence} must be a sequence of strings. These strings ++represent the possible values for the parameter. ++ ++If @var{parameter-class} is not @code{PARAM_ENUM}, then the presence ++of a fourth argument will cause an exception to be thrown. ++ ++The help text for the new parameter is taken from the Python ++documentation string for the parameter's class, if there is one. If ++there is no documentation string, a default value is used. ++@end defmethod ++ ++@defivar Parameter set_doc ++If this attribute exists, and is a string, then its value is used as ++the help text for this parameter's @code{set} command. The value is ++examined when @code{Parameter.__init__} is invoked; subsequent changes ++have no effect. ++@end defivar ++ ++@defivar Parameter show_doc ++If this attribute exists, and is a string, then its value is used as ++the help text for this parameter's @code{show} command. The value is ++examined when @code{Parameter.__init__} is invoked; subsequent changes ++have no effect. ++@end defivar ++ ++@defivar Parameter value ++The @code{value} attribute holds the underlying value of the ++parameter. It can be read and assigned to just as any other ++attribute. @value{GDBN} does validation when assignments are made. ++@end defivar ++ ++ ++When a new parameter is defined, its type must be specified. The ++available types are represented by constants defined in the @code{gdb} ++module: ++ ++@table @code ++@findex PARAM_BOOLEAN ++@findex gdb.PARAM_BOOLEAN ++@item PARAM_BOOLEAN ++The value is a plain boolean. The Python boolean values, @code{True} ++and @code{False} are the only valid values. ++ ++@findex PARAM_AUTO_BOOLEAN ++@findex gdb.PARAM_AUTO_BOOLEAN ++@item PARAM_AUTO_BOOLEAN ++The value has three possible states: true, false, and @samp{auto}. In ++Python, true and false are represented using boolean constants, and ++@samp{auto} is represented using @code{None}. ++ ++@findex PARAM_UINTEGER ++@findex gdb.PARAM_UINTEGER ++@item PARAM_UINTEGER ++The value is an unsigned integer. The value of 0 should be ++interpreted to mean ``unlimited''. ++ ++@findex PARAM_INTEGER ++@findex gdb.PARAM_INTEGER ++@item PARAM_INTEGER ++The value is a signed integer. The value of 0 should be interpreted ++to mean ``unlimited''. ++ ++@findex PARAM_STRING ++@findex gdb.PARAM_STRING ++@item PARAM_STRING ++The value is a string. When the user modifies the string, escapes are ++translated. ++ ++@findex PARAM_STRING_NOESCAPE ++@findex gdb.PARAM_STRING_NOESCAPE ++@item PARAM_STRING_NOESCAPE ++The value is a string. When the user modifies the string, escapes are ++passed through untranslated. ++ ++@findex PARAM_OPTIONAL_FILENAME ++@findex gdb.PARAM_OPTIONAL_FILENAME ++@item PARAM_OPTIONAL_FILENAME ++The value is a either a filename (a string), or @code{None}. ++ ++@findex PARAM_FILENAME ++@findex gdb.PARAM_FILENAME ++@item PARAM_FILENAME ++The value is a filename (a string). ++ ++@findex PARAM_ZINTEGER ++@findex gdb.PARAM_ZINTEGER ++@item PARAM_ZINTEGER ++The value is an integer. This is like @code{PARAM_INTEGER}, except 0 ++is interpreted as itself. ++ ++@findex PARAM_ENUM ++@findex gdb.PARAM_ENUM ++@item PARAM_ENUM ++The value is a string, which must be one of a collection string ++constants provided when the parameter is created. ++@end table ++ ++@node Functions In Python ++@subsubsection Writing new convenience functions ++ ++@cindex writing convenience functions ++@cindex convenience functions in python ++@cindex python convenience functions ++@tindex gdb.Function ++@tindex Function ++You can implement new convenience functions (@pxref{Convenience Vars}) ++in Python. A convenience function is an instance of a subclass of the ++class @code{gdb.Function}. ++ ++@defmethod Function __init__ name ++The initializer for @code{Function} registers the new function with ++@value{GDBN}. The argument @var{name} is the name of the function, ++a string. The function will be visible to the user as a convenience ++variable of type @code{internal function}, whose name is the same as ++the given @var{name}. ++ ++The documentation for the new function is taken from the documentation ++string for the new class. ++@end defmethod ++ ++@defmethod Function invoke @var{*args} ++When a convenience function is evaluated, its arguments are converted ++to instances of @code{gdb.Value}, and then the function's ++@code{invoke} method is called. Note that @value{GDBN} does not ++predetermine the arity of convenience functions. Instead, all ++available arguments are passed to @code{invoke}, following the ++standard Python calling convention. In particular, a convenience ++function can have default values for parameters without ill effect. ++ ++The return value of this method is used as its value in the enclosing ++expression. If an ordinary Python value is returned, it is converted ++to a @code{gdb.Value} following the usual rules. ++@end defmethod ++ ++The following code snippet shows how a trivial convenience function can ++be implemented in Python: ++ ++@smallexample ++class Greet (gdb.Function): ++ """Return string to greet someone. ++Takes a name as argument.""" ++ ++ def __init__ (self): ++ super (Greet, self).__init__ ("greet") ++ ++ def invoke (self, name): ++ return "Hello, %s!" % name.string () ++ ++Greet () ++@end smallexample ++ ++The last line instantiates the class, and is necessary to trigger the ++registration of the function with @value{GDBN}. Depending on how the ++Python code is read into @value{GDBN}, you may need to import the ++@code{gdb} module explicitly. ++ ++@node Objfiles In Python ++@subsubsection Objfiles In Python ++ ++@cindex objfiles in python ++@cindex python objfiles ++@tindex gdb.Objfile ++@tindex Objfile ++@value{GDBN} loads symbols for an inferior from various ++symbol-containing files. These include the primary executable file, ++any shared libraries used by the inferior, and any separate debug info ++files. @value{GDBN} calls these symbol-containing files ++@dfn{objfiles}. ++ ++Each objfile is represented by an instance of the @code{gdb.Objfile} ++class. ++ ++@defivar Objfile filename ++The file name of the objfile as a string. ++@end defivar ++ ++@defivar Objfile pretty_printers ++The @code{pretty_printers} attribute is used to look up ++pretty-printers by type. This is a dictionary which maps regular ++expressions (strings) to pretty-printing objects. @xref{Pretty ++Printing}, for more information. ++@end defivar ++ ++@node Breakpoints In Python ++@subsubsection Manipulating breakpoints using Python ++ ++@cindex breakpoints in python ++@cindex python breakpoints ++@tindex gdb.Breakpoint ++@tindex Breakpoint ++Python code can manipulate breakpoints via the @code{gdb.Breakpoint} ++class. ++ ++@defmethod Breakpoint __init__ location ++Create a new breakpoint. @var{location} is a string naming the ++location of the breakpoint. The contents can be any location ++recognized by the @code{break} command. ++@end defmethod ++ ++@defmethod Breakpoint is_valid ++Return @code{True} if this @code{Breakpoint} object is valid, ++@code{False} otherwise. A @code{Breakpoint} object can become invalid ++if the user deletes the breakpoint. In this case, the object still ++exists, but the underlying breakpoint does not. ++@end defmethod ++ ++@defivar Breakpoint enabled ++This attribute is @code{True} if the breakpoint is enabled, and ++@code{False} otherwise. This attribute is writable. ++@end defivar ++ ++@defivar Breakpoint silent ++This attribute is @code{True} if the breakpoint is silent, and ++@code{False} otherwise. This attribute is writable. ++ ++Note that a breakpoint can also be silent if it has commands and the ++first command is @code{silent}. This is not reported by the ++@code{silent} attribute. ++@end defivar ++ ++@defivar Breakpoint thread ++If the breakpoint is thread-specific, this attribute holds the thread ++id. If the breakpoint is not thread-specific, this attribute is ++@code{None}. This attribute is writable. ++@end defivar ++ ++@defivar Breakpoint ignore_count ++This attribute holds the ignore count for the breakpoint, an integer. ++This attribute is writable. ++@end defivar ++ ++@defivar Breakpoint number ++This attribute holds the breakpoint's number -- the identifier used by ++the user to manipulate the breakpoint. This attribute is not writable. ++@end defivar ++ ++@defivar Breakpoint hit_count ++This attribute holds the hit count for the breakpoint, an integer. ++This attribute is writable, but currently it can only be set to zero. ++@end defivar ++ ++@defivar Breakpoint location ++This attribute holds the location of the breakpoint, as specified by ++the user. It is a string. This attribute is not writable. ++@end defivar ++ ++@defivar Breakpoint condition ++This attribute holds the condition of the breakpoint, as specified by ++the user. It is a string. If there is no condition, this attribute's ++value is @code{None}. This attribute is writable. ++@end defivar ++ ++@defivar Breakpoint commands ++This attribute holds the commands attached to the breakpoint. If ++there are commands, this returns a string holding all the commands, ++separated by newlines. If there are no commands, this attribute is ++@code{None}. This attribute is not writable. ++@end defivar ++ ++@node Frames In Python ++@subsubsection Accessing inferior stack frames from Python. ++ ++@cindex frames in python ++@tindex gdb.Frame ++@tindex Frame ++When the debugged program stops, @value{GDBN} is able to analyse its call ++stack (@pxref{Frames,,Stack frames}). The @code{gdb.Frame} class ++represents a frame in the stack. You can get a tuple containing all the ++frames in the stack with the @code{gdb.frames} function, the newest ++frame with the @code{gdb.newest_frame} function, and the selected frame ++with the @code{gdb.selected_frame} function ++(see @xref{Selection,,Selecting a Frame}.) See ++@xref{Basic Python,,Basic Python}. ++ ++A @code{gdb.Frame} object has the following methods: ++ ++@table @code ++@defmethod Frame equals @code{frame} ++Compare frames. ++@end defmethod ++ ++@defmethod Frame is_valid ++Returns true if the @code{gdb.Frame} object is valid, false if not. ++A frame object can become invalid if the frame it refers to doesn't ++exist anymore in the inferior. All @code{gdb.Frame} methods will throw ++an exception if it is invalid at the time the method call is made. ++@end defmethod ++ ++@defmethod Frame name ++Returns the function name of the frame, or @code{None} if it can't be ++obtained. ++@end defmethod ++ ++@defmethod Frame type ++Returns the type of the frame. The value can be one of ++@code{gdb.NORMAL_FRAME}, @code{gdb.DUMMY_FRAME}, @code{gdb.SIGTRAMP_FRAME} ++or @code{gdb.SENTINEL_FRAME}. ++@end defmethod ++ ++@defmethod Frame unwind_stop_reason ++Return an integer representing the reason why it's not possible to find ++frames older than this. Use @code{gdb.frame_stop_reason_string} to convert ++the value returned by this function to a string. ++@end defmethod ++ ++@defmethod Frame pc ++Returns the frame's resume address. ++@end defmethod ++ ++@defmethod Frame block ++Returns the frame's code block. @c (see @xref{Block,,Code Blocks and Scopes}). ++@end defmethod ++ ++@defmethod Frame address_in_block ++Returns an address which falls within the frame's code block. ++@end defmethod ++ ++@defmethod Frame older ++Return the frame immediately older (outer) to this frame. ++@end defmethod ++ ++@defmethod Frame newer ++Return the frame immediately newer (inner) to this frame. ++@end defmethod ++ ++@defmethod Frame find_sal ++Return the frame's symtab and line object. @c (see @xref{Symtab_and_line,, Symtab and line}). ++@end defmethod ++ ++@defmethod Frame read_var @var{variable} ++Return the value of the given variable in this frame. @code{variable} can be ++either a string or a @code{gdb.Symbol} object. @c (@pxref{Symbols In Python}). ++@end defmethod ++@end table ++ + @node Interpreters + @chapter Command Interpreters + @cindex command interpreters +@@ -22273,6 +23416,103 @@ Unfreezing a variable does not update it, only subsequent + (gdb) + @end smallexample + ++@subheading The @code{-var-set-visualizer} command ++@findex -var-set-visualizer ++@anchor{-var-set-visualizer} ++ ++@subsubheading Synopsis ++ ++@smallexample ++ -var-set-visualizer @var{name} @var{visualizer} ++@end smallexample ++ ++@subheading The @code{-var-set-child-range} command ++@findex -var-set-child-range ++@anchor{-var-set-child-range} ++ ++Set a visualizer for the variable object @var{name}. ++ ++@var{visualizer} is the visualizer to use. The special value ++@samp{None} means to disable any visualizer in use. ++ ++If not @samp{None}, @var{visualizer} must be a Python expression. ++This expression must evaluate to a callable object which accepts a ++single argument. @value{GDBN} will call this object with the value of ++the varobj @var{name} as an argument. This function must return an ++object which conforms to the pretty-printing interface (@pxref{Pretty ++Printing}). ++ ++The pre-defined function @code{gdb.default_visualizer} may be used ++to select a visualizer according to the type of the varobj. This is ++called when a varobj is created, and so ordinarily is not needed. ++ ++@code{gdb.default_visualizer} looks in the global dictionary named ++@code{gdb.pretty_printers}. ++ ++This feature is only available if Python support is enabled. ++ ++@subsubheading Example ++ ++Resetting the visualizer: ++ ++@smallexample ++(gdb) ++-var-set-visualizer V None ++^done ++@end smallexample ++ ++Reselecting the default (type-based) visualizer: ++ ++@smallexample ++(gdb) ++-var-set-visualizer V gdb.default_visualizer ++^done ++@end smallexample ++ ++Suppose @code{SomeClass} is a visualizer class. A lambda expression ++can be used to instantiate this class for a varobj: ++ ++@smallexample ++(gdb) ++-var-set-visualizer V "lambda val: SomeClass()" ++^done ++@end smallexample ++ ++@subsubheading Synopsis ++ ++@smallexample ++ -var-set-child-range @var{name} @var{from} @var{to} ++@end smallexample ++ ++Select a sub-range of the children of the variable object @var{name}; ++future calls to @code{-var-list-children} will only report the ++selected range of children. This allows an MI consumer to avoid ++inefficiencies if the varobj has very many children. ++ ++If either @var{from} or @var{to} is less than zero, then sub-range ++selection is disabled, and @code{-var-list-children} will report all ++children. ++ ++Otherwise, @var{from} and @var{to} are indexes into the array of ++children. Children starting at @var{from} and stopping jsut before ++@var{to} will be reported. ++ ++@subsubheading Example ++ ++@smallexample ++(gdb) ++ -var-list-children n ++ ^done,numchild=3,children=[@{name="a",numchild=0,type="int"@}, ++ @{name="b",numchild=0,type="int"@}, ++ @{name="c",numchild=0,type="int"@}] ++(gdb) ++ -var-set-child-range n 1 2 ++(gdb) ++ -var-list-children n ++ ^done,numchild=3,children=[@{name="b",numchild=0,type="int"@}, ++ @{name="c",numchild=0,type="int"@}] ++@end smallexample ++ + + @c %%%%%%%%%%%%%%%%%%%%%%%%%%%% SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + @node GDB/MI Data Manipulation +@@ -23832,6 +25072,10 @@ as possible presense of the @code{frozen} field in the output + of @code{-varobj-create}. + @item pending-breakpoints + Indicates presence of the @option{-f} option to the @code{-break-insert} command. ++@item python ++Indicates presence of Python scripting support, Python-based ++pretty-printing commands, and possible presence of the ++@samp{display_hint} field in the output of @code{-var-list-children} + @item thread-info + Indicates presence of the @code{-thread-info} command. + +@@ -25402,28 +26646,6 @@ data in a @file{gmon.out} file, be sure to move it to a safe location. + Configuring with @samp{--enable-profiling} arranges for @value{GDBN} to be + compiled with the @samp{-pg} compiler option. + +-@kindex maint set linux-async +-@kindex maint show linux-async +-@cindex asynchronous support +-@item maint set linux-async +-@itemx maint show linux-async +-Control the GNU/Linux native asynchronous support +-(@pxref{Background Execution}) of @value{GDBN}. +- +-GNU/Linux native asynchronous support will be disabled until you use +-the @samp{maint set linux-async} command to enable it. +- +-@kindex maint set remote-async +-@kindex maint show remote-async +-@cindex asynchronous support +-@item maint set remote-async +-@itemx maint show remote-async +-Control the remote asynchronous support +-(@pxref{Background Execution}) of @value{GDBN}. +- +-Remote asynchronous support will be disabled until you use +-the @samp{maint set remote-async} command to enable it. +- + @kindex maint show-debug-regs + @cindex x86 hardware debug registers + @item maint show-debug-regs +diff --git a/gdb/dwarf2-frame.c b/gdb/dwarf2-frame.c +index ce11d89..eaa6a13 100644 +--- a/gdb/dwarf2-frame.c ++++ b/gdb/dwarf2-frame.c +@@ -38,6 +38,7 @@ + + #include "complaints.h" + #include "dwarf2-frame.h" ++#include "addrmap.h" + + struct comp_unit; + +@@ -1499,6 +1500,14 @@ dwarf2_frame_find_fde (CORE_ADDR *pc) + struct dwarf2_fde *fde; + CORE_ADDR offset; + ++ if (objfile->quick_addrmap) ++ { ++ if (!addrmap_find (objfile->quick_addrmap, *pc)) ++ continue; ++ } ++ /* FIXME: Read-in only .debug_frame/.eh_frame without .debug_info? */ ++ require_partial_symbols (objfile); ++ + fde = objfile_data (objfile, dwarf2_frame_objfile_data); + if (fde == NULL) + continue; +diff --git a/gdb/dwarf2expr.c b/gdb/dwarf2expr.c +index 75a4ec7..aa8ab33 100644 +--- a/gdb/dwarf2expr.c ++++ b/gdb/dwarf2expr.c +@@ -752,6 +752,13 @@ execute_stack_op (struct dwarf_expr_context *ctx, + ctx->initialized = 0; + goto no_push; + ++ case DW_OP_push_object_address: ++ if (ctx->get_object_address == NULL) ++ error (_("DWARF-2 expression error: DW_OP_push_object_address must " ++ "have a value to push.")); ++ result = (ctx->get_object_address) (ctx->baton); ++ break; ++ + default: + error (_("Unhandled dwarf expression opcode 0x%x"), op); + } +diff --git a/gdb/dwarf2expr.h b/gdb/dwarf2expr.h +index 7047922..a287b6f 100644 +--- a/gdb/dwarf2expr.h ++++ b/gdb/dwarf2expr.h +@@ -67,10 +67,10 @@ struct dwarf_expr_context + The result must be live until the current expression evaluation + is complete. */ + unsigned char *(*get_subr) (void *baton, off_t offset, size_t *length); ++#endif + + /* Return the `object address' for DW_OP_push_object_address. */ + CORE_ADDR (*get_object_address) (void *baton); +-#endif + + /* The current depth of dwarf expression recursion, via DW_OP_call*, + DW_OP_fbreg, DW_OP_push_object_address, etc., and the maximum +diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c +index cad3db8..2251e48 100644 +--- a/gdb/dwarf2loc.c ++++ b/gdb/dwarf2loc.c +@@ -107,6 +107,9 @@ struct dwarf_expr_baton + { + struct frame_info *frame; + struct objfile *objfile; ++ /* From DW_TAG_variable's DW_AT_location (not DW_TAG_type's ++ DW_AT_data_location) for DW_OP_push_object_address. */ ++ CORE_ADDR object_address; + }; + + /* Helper functions for dwarf2_evaluate_loc_desc. */ +@@ -163,22 +166,32 @@ dwarf_expr_frame_base (void *baton, gdb_byte **start, size_t * length) + *start = find_location_expression (symbaton, length, + get_frame_address_in_block (frame)); + } +- else ++ else if (SYMBOL_OPS (framefunc) == &dwarf2_locexpr_funcs) + { + struct dwarf2_locexpr_baton *symbaton; ++ + symbaton = SYMBOL_LOCATION_BATON (framefunc); +- if (symbaton != NULL) +- { +- *length = symbaton->size; +- *start = symbaton->data; +- } +- else +- *start = NULL; ++ gdb_assert (symbaton != NULL); ++ *start = symbaton->data; ++ *length = symbaton->size; ++ } ++ else if (SYMBOL_OPS (framefunc) == &dwarf2_missing_funcs) ++ { ++ struct dwarf2_locexpr_baton *symbaton; ++ ++ symbaton = SYMBOL_LOCATION_BATON (framefunc); ++ gdb_assert (symbaton == NULL); ++ *start = NULL; ++ *length = 0; /* unused */ + } ++ else ++ internal_error (__FILE__, __LINE__, ++ _("Unsupported SYMBOL_OPS %p for \"%s\""), ++ SYMBOL_OPS (framefunc), SYMBOL_PRINT_NAME (framefunc)); + + if (*start == NULL) + error (_("Could not find the frame base for \"%s\"."), +- SYMBOL_NATURAL_NAME (framefunc)); ++ SYMBOL_PRINT_NAME (framefunc)); + } + + /* Using the objfile specified in BATON, find the address for the +@@ -191,6 +204,119 @@ dwarf_expr_tls_address (void *baton, CORE_ADDR offset) + return target_translate_tls_address (debaton->objfile, offset); + } + ++static CORE_ADDR ++dwarf_expr_object_address (void *baton) ++{ ++ struct dwarf_expr_baton *debaton = baton; ++ ++ /* The message is suppressed in DWARF_BLOCK_EXEC. */ ++ if (debaton->object_address == 0) ++ error (_("Cannot resolve DW_OP_push_object_address for a missing object")); ++ ++ return debaton->object_address; ++} ++ ++/* Address of the variable we are currently referring to. It is set from ++ DW_TAG_variable's DW_AT_location (not DW_TAG_type's DW_AT_data_location) for ++ DW_OP_push_object_address. */ ++ ++static CORE_ADDR object_address; ++ ++/* Callers use object_address_set while their callers use the result set so we ++ cannot run the cleanup at the local block of our direct caller. Still we ++ should reset OBJECT_ADDRESS at least for the next GDB command. */ ++ ++static void ++object_address_cleanup (void *prev_save_voidp) ++{ ++ CORE_ADDR *prev_save = prev_save_voidp; ++ ++ object_address = *prev_save; ++ xfree (prev_save); ++} ++ ++/* Set the base address - DW_AT_location - of a variable. It is being later ++ used to derive other object addresses by DW_OP_push_object_address. ++ ++ It would be useful to sanity check ADDRESS - such as for some objects with ++ unset VALUE_ADDRESS - but some valid addresses may be zero (such as first ++ objects in relocatable .o files). */ ++ ++void ++object_address_set (CORE_ADDR address) ++{ ++ CORE_ADDR *prev_save; ++ ++ prev_save = xmalloc (sizeof *prev_save); ++ *prev_save = object_address; ++ make_cleanup (object_address_cleanup, prev_save); ++ ++ object_address = address; ++} ++ ++/* Evaluate DWARF expression at DATA ... DATA + SIZE with its result readable ++ by dwarf_expr_fetch (RETVAL, 0). FRAME parameter can be NULL to call ++ get_selected_frame to find it. Returned dwarf_expr_context freeing is ++ pushed on the cleanup chain. */ ++ ++static struct dwarf_expr_context * ++dwarf_expr_prep_ctx (struct frame_info *frame, gdb_byte *data, ++ unsigned short size, struct dwarf2_per_cu_data *per_cu) ++{ ++ struct dwarf_expr_context *ctx; ++ struct dwarf_expr_baton baton; ++ ++ if (!frame) ++ frame = get_selected_frame (NULL); ++ ++ baton.frame = frame; ++ baton.objfile = dwarf2_per_cu_objfile (per_cu); ++ baton.object_address = object_address; ++ ++ ctx = new_dwarf_expr_context (); ++ ctx->gdbarch = get_objfile_arch (baton.objfile); ++ ctx->addr_size = dwarf2_per_cu_addr_size (per_cu); ++ ctx->baton = &baton; ++ ctx->read_reg = dwarf_expr_read_reg; ++ ctx->read_mem = dwarf_expr_read_mem; ++ ctx->get_frame_base = dwarf_expr_frame_base; ++ ctx->get_tls_address = dwarf_expr_tls_address; ++ ctx->get_object_address = dwarf_expr_object_address; ++ ++ make_cleanup ((make_cleanup_ftype *) free_dwarf_expr_context, ctx); ++ ++ dwarf_expr_eval (ctx, data, size); ++ ++ /* It was used only during dwarf_expr_eval. */ ++ ctx->baton = NULL; ++ ++ return ctx; ++} ++ ++/* Evaluate DWARF expression at DLBATON expecting it produces exactly one ++ CORE_ADDR result on the DWARF stack stack. */ ++ ++CORE_ADDR ++dwarf_locexpr_baton_eval (struct dwarf2_locexpr_baton *dlbaton) ++{ ++ struct dwarf_expr_context *ctx; ++ CORE_ADDR retval; ++ struct cleanup *back_to = make_cleanup (null_cleanup, 0); ++ ++ ctx = dwarf_expr_prep_ctx (NULL, dlbaton->data, dlbaton->size, ++ dlbaton->per_cu); ++ if (ctx->num_pieces > 0) ++ error (_("DW_OP_*piece is unsupported for DW_FORM_block")); ++ else if (ctx->in_reg) ++ error (_("Register result is unsupported for DW_FORM_block")); ++ ++ retval = dwarf_expr_fetch (ctx, 0); ++ ++ do_cleanups (back_to); ++ ++ return retval; ++} ++ + /* Evaluate a location description, starting at DATA and with length + SIZE, to find the current location of variable VAR in the context + of FRAME. */ +@@ -200,8 +326,8 @@ dwarf2_evaluate_loc_desc (struct symbol *var, struct frame_info *frame, + struct dwarf2_per_cu_data *per_cu) + { + struct value *retval; +- struct dwarf_expr_baton baton; + struct dwarf_expr_context *ctx; ++ struct cleanup *back_to = make_cleanup (null_cleanup, 0); + + if (size == 0) + { +@@ -211,19 +337,8 @@ dwarf2_evaluate_loc_desc (struct symbol *var, struct frame_info *frame, + return retval; + } + +- baton.frame = frame; +- baton.objfile = dwarf2_per_cu_objfile (per_cu); ++ ctx = dwarf_expr_prep_ctx (frame, data, size, per_cu); + +- ctx = new_dwarf_expr_context (); +- ctx->gdbarch = get_objfile_arch (baton.objfile); +- ctx->addr_size = dwarf2_per_cu_addr_size (per_cu); +- ctx->baton = &baton; +- ctx->read_reg = dwarf_expr_read_reg; +- ctx->read_mem = dwarf_expr_read_mem; +- ctx->get_frame_base = dwarf_expr_frame_base; +- ctx->get_tls_address = dwarf_expr_tls_address; +- +- dwarf_expr_eval (ctx, data, size); + if (ctx->num_pieces > 0) + { + int i; +@@ -261,15 +376,19 @@ dwarf2_evaluate_loc_desc (struct symbol *var, struct frame_info *frame, + { + CORE_ADDR address = dwarf_expr_fetch (ctx, 0); + ++ /* object_address_set called here is required in ALLOCATE_VALUE's ++ CHECK_TYPEDEF for the object's possible DW_OP_push_object_address. */ ++ object_address_set (address); ++ + retval = allocate_value (SYMBOL_TYPE (var)); + VALUE_LVAL (retval) = lval_memory; + set_value_lazy (retval, 1); +- VALUE_ADDRESS (retval) = address; ++ set_value_address (retval, address); + } + + set_value_initialized (retval, ctx->initialized); + +- free_dwarf_expr_context (ctx); ++ do_cleanups (back_to); + + return retval; + } +@@ -587,7 +706,7 @@ static int + loclist_describe_location (struct symbol *symbol, struct ui_file *stream) + { + /* FIXME: Could print the entire list of locations. */ +- fprintf_filtered (stream, "a variable with multiple locations"); ++ fprintf_filtered (stream, _("a variable with multiple locations")); + return 1; + } + +@@ -603,16 +722,56 @@ loclist_tracepoint_var_ref (struct symbol * symbol, struct agent_expr * ax, + + data = find_location_expression (dlbaton, &size, ax->scope); + if (data == NULL) +- error (_("Variable \"%s\" is not available."), SYMBOL_NATURAL_NAME (symbol)); ++ error (_("Variable \"%s\" is not available."), SYMBOL_PRINT_NAME (symbol)); + + dwarf2_tracepoint_var_ref (symbol, ax, value, data, size); + } + +-/* The set of location functions used with the DWARF-2 expression +- evaluator and location lists. */ ++/* The set of location functions used with the DWARF-2 location lists. */ + const struct symbol_ops dwarf2_loclist_funcs = { + loclist_read_variable, + loclist_read_needs_frame, + loclist_describe_location, + loclist_tracepoint_var_ref + }; ++ ++static struct value * ++missing_read_variable (struct symbol *symbol, struct frame_info *frame) ++{ ++ struct dwarf2_loclist_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol); ++ ++ gdb_assert (dlbaton == NULL); ++ error (_("Unable to resolve variable \"%s\""), SYMBOL_PRINT_NAME (symbol)); ++} ++ ++static int ++missing_read_needs_frame (struct symbol *symbol) ++{ ++ return 0; ++} ++ ++static int ++missing_describe_location (struct symbol *symbol, struct ui_file *stream) ++{ ++ fprintf_filtered (stream, _("a variable we are unable to resolve")); ++ return 1; ++} ++ ++static void ++missing_tracepoint_var_ref (struct symbol *symbol, struct agent_expr *ax, ++ struct axs_value *value) ++{ ++ struct dwarf2_loclist_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol); ++ ++ gdb_assert (dlbaton == NULL); ++ error (_("Unable to resolve variable \"%s\""), SYMBOL_PRINT_NAME (symbol)); ++} ++ ++/* The set of location functions used with the DWARF-2 evaluator when we are ++ unable to resolve the symbols. */ ++const struct symbol_ops dwarf2_missing_funcs = { ++ missing_read_variable, ++ missing_read_needs_frame, ++ missing_describe_location, ++ missing_tracepoint_var_ref ++}; +diff --git a/gdb/dwarf2loc.h b/gdb/dwarf2loc.h +index 76577f1..bf46761 100644 +--- a/gdb/dwarf2loc.h ++++ b/gdb/dwarf2loc.h +@@ -71,5 +71,11 @@ struct dwarf2_loclist_baton + + extern const struct symbol_ops dwarf2_locexpr_funcs; + extern const struct symbol_ops dwarf2_loclist_funcs; ++extern const struct symbol_ops dwarf2_missing_funcs; ++ ++extern void object_address_set (CORE_ADDR address); ++ ++extern CORE_ADDR dwarf_locexpr_baton_eval ++ (struct dwarf2_locexpr_baton *dlbaton); + + #endif /* dwarf2loc.h */ +diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c +index 55868da..de93d08 100644 +--- a/gdb/dwarf2read.c ++++ b/gdb/dwarf2read.c +@@ -1,8 +1,7 @@ + /* DWARF 2 debugging format support for GDB. + + Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, +- 2004, 2005, 2006, 2007, 2008, 2009 +- Free Software Foundation, Inc. ++ 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. + + Adapted by Gary Funck (gary@intrepid.com), Intrepid Technology, + Inc. with support from Florida State University (under contract +@@ -47,6 +46,9 @@ + #include "command.h" + #include "gdbcmd.h" + #include "addrmap.h" ++#include "f-lang.h" ++#include "c-lang.h" ++#include "typeprint.h" + + #include + #include "gdb_string.h" +@@ -103,7 +105,7 @@ typedef struct pubnames_header + _PUBNAMES_HEADER; + #define _ACTUAL_PUBNAMES_HEADER_SIZE 13 + +-/* .debug_pubnames header ++/* .debug_aranges header + Because of alignment constraints, this structure has padding and cannot + be mapped directly onto the beginning of the .debug_info section. */ + typedef struct aranges_header +@@ -299,9 +301,6 @@ struct dwarf2_cu + /* Hash table holding all the loaded partial DIEs. */ + htab_t partial_dies; + +- /* `.debug_ranges' offset for this `DW_TAG_compile_unit' DIE. */ +- unsigned int ranges_offset; +- + /* Storage for things with the same lifetime as this read-in compilation + unit, including partial DIEs. */ + struct obstack comp_unit_obstack; +@@ -349,9 +348,6 @@ struct dwarf2_cu + DIEs for namespaces, we don't need to try to infer them + from mangled names. */ + unsigned int has_namespace_info : 1; +- +- /* Field `ranges_offset' is filled in; flag as the value may be zero. */ +- unsigned int has_ranges_offset : 1; + }; + + /* Persistent data held for a compilation unit, even when not +@@ -451,17 +447,12 @@ struct partial_die_info + /* DWARF-2 tag for this DIE. */ + ENUM_BITFIELD(dwarf_tag) tag : 16; + +- /* Language code associated with this DIE. This is only used +- for the compilation unit DIE. */ +- unsigned int language : 8; +- + /* Assorted flags describing the data found in this DIE. */ + unsigned int has_children : 1; + unsigned int is_external : 1; + unsigned int is_declaration : 1; + unsigned int has_type : 1; + unsigned int has_specification : 1; +- unsigned int has_stmt_list : 1; + unsigned int has_pc_info : 1; + + /* Flag set if the SCOPE field of this structure has been +@@ -472,10 +463,12 @@ struct partial_die_info + unsigned int has_byte_size : 1; + + /* The name of this DIE. Normally the value of DW_AT_name, but +- sometimes DW_TAG_MIPS_linkage_name or a string computed in some +- other fashion. */ ++ sometimes a default name for unnamed DIEs. */ + char *name; +- char *dirname; ++ ++ /* The linkage name of this DIE, from DW_AT_MIPS_linkage_name, or ++ NULL if no linkage name was present. */ ++ char *linkage_name; + + /* The scope to prepend to our children. This is generally + allocated on the comp_unit_obstack, so will disappear +@@ -498,9 +491,6 @@ struct partial_die_info + DW_AT_extension). */ + unsigned int spec_offset; + +- /* If HAS_STMT_LIST, the offset of the Line Number Information data. */ +- unsigned int line_offset; +- + /* Pointers to this DIE's parent, first child, and next sibling, + if any. */ + struct partial_die_info *die_parent, *die_child, *die_sibling; +@@ -523,6 +513,15 @@ struct attr_abbrev + ENUM_BITFIELD(dwarf_form) form : 16; + }; + ++/* Additional GDB-specific attribute forms. */ ++enum ++ { ++ /* A string which has been updated to GDB's internal ++ representation (e.g. converted to canonical form) and does not ++ need to be updated again. */ ++ GDB_FORM_cached_string = 0xff ++ }; ++ + /* Attributes have a name and a value */ + struct attribute + { +@@ -756,7 +755,7 @@ static void dwarf2_create_include_psymtab (char *, struct partial_symtab *, + struct objfile *); + + static void dwarf2_build_include_psymtabs (struct dwarf2_cu *, +- struct partial_die_info *, ++ struct die_info *, + struct partial_symtab *); + + static void dwarf2_build_psymtabs_hard (struct objfile *, int); +@@ -768,6 +767,9 @@ static void scan_partial_symbols (struct partial_die_info *, + static void add_partial_symbol (struct partial_die_info *, + struct dwarf2_cu *); + ++static gdb_byte *read_comp_unit_head (struct comp_unit_head *, gdb_byte *, ++ bfd *); ++ + static int pdi_needs_namespace (enum dwarf_tag tag); + + static void add_partial_namespace (struct partial_die_info *pdi, +@@ -794,6 +796,10 @@ static void dwarf2_psymtab_to_symtab (struct partial_symtab *); + + static void psymtab_to_symtab_1 (struct partial_symtab *); + ++static gdb_byte *dwarf2_read_section_1 (struct objfile *objfile, ++ struct obstack *obstack, ++ asection *sectp); ++ + gdb_byte *dwarf2_read_section (struct objfile *, asection *); + + static void dwarf2_read_abbrevs (bfd *abfd, struct dwarf2_cu *cu); +@@ -929,7 +935,8 @@ static int dwarf2_ranges_read (unsigned, CORE_ADDR *, CORE_ADDR *, + struct dwarf2_cu *, struct partial_symtab *); + + static int dwarf2_get_pc_bounds (struct die_info *, +- CORE_ADDR *, CORE_ADDR *, struct dwarf2_cu *); ++ CORE_ADDR *, CORE_ADDR *, struct dwarf2_cu *, ++ struct partial_symtab *pst); + + static void get_scope_pc_bounds (struct die_info *, + CORE_ADDR *, CORE_ADDR *, +@@ -962,6 +969,8 @@ static void read_namespace (struct die_info *die, struct dwarf2_cu *); + + static void read_module (struct die_info *die, struct dwarf2_cu *cu); + ++static void read_import_statement (struct die_info *die, struct dwarf2_cu *); ++ + static const char *namespace_name (struct die_info *die, + int *is_anonymous, struct dwarf2_cu *); + +@@ -993,6 +1002,9 @@ static void process_die (struct die_info *, struct dwarf2_cu *); + + static char *dwarf2_linkage_name (struct die_info *, struct dwarf2_cu *); + ++static char *dwarf2_canonicalize_name (char *, struct dwarf2_cu *, ++ struct obstack *); ++ + static char *dwarf2_name (struct die_info *die, struct dwarf2_cu *); + + static struct die_info *dwarf2_extension (struct die_info *die, +@@ -1030,7 +1042,14 @@ static void store_in_ref_table (struct die_info *, + + static unsigned int dwarf2_get_ref_die_offset (struct attribute *); + +-static int dwarf2_get_attr_constant_value (struct attribute *, int); ++enum dwarf2_get_attr_constant_value ++ { ++ dwarf2_attr_unknown, ++ dwarf2_attr_const, ++ dwarf2_attr_block ++ }; ++static enum dwarf2_get_attr_constant_value dwarf2_get_attr_constant_value ++ (struct attribute *attr, int *val_return); + + static struct die_info *follow_die_ref (struct die_info *, + struct attribute *, +@@ -1085,6 +1104,9 @@ static void age_cached_comp_units (void); + + static void free_one_cached_comp_unit (void *); + ++static void fetch_die_type_attrs (struct die_info *die, struct type *type, ++ struct dwarf2_cu *cu); ++ + static struct type *set_die_type (struct die_info *, struct type *, + struct dwarf2_cu *); + +@@ -1104,19 +1126,28 @@ static void dwarf2_clear_marks (struct dwarf2_per_cu_data *); + + static struct type *get_die_type (struct die_info *die, struct dwarf2_cu *cu); + ++static struct dwarf2_locexpr_baton *dwarf2_attr_to_locexpr_baton ++ (struct attribute *attr, struct dwarf2_cu *cu); ++ + /* Try to locate the sections we need for DWARF 2 debugging + information and return true if we have enough to do something. */ + + int + dwarf2_has_info (struct objfile *objfile) + { +- struct dwarf2_per_objfile *data; ++ int update_sizes = 0; + + /* Initialize per-objfile state. */ +- data = obstack_alloc (&objfile->objfile_obstack, sizeof (*data)); +- memset (data, 0, sizeof (*data)); +- set_objfile_data (objfile, dwarf2_objfile_data_key, data); +- dwarf2_per_objfile = data; ++ dwarf2_per_objfile = objfile_data (objfile, dwarf2_objfile_data_key); ++ if (!dwarf2_per_objfile) ++ { ++ struct dwarf2_per_objfile *data ++ = obstack_alloc (&objfile->objfile_obstack, sizeof (*data)); ++ memset (data, 0, sizeof (*data)); ++ set_objfile_data (objfile, dwarf2_objfile_data_key, data); ++ dwarf2_per_objfile = data; ++ update_sizes = 1; ++ } + + dwarf_info_section = 0; + dwarf_abbrev_section = 0; +@@ -1127,8 +1158,9 @@ dwarf2_has_info (struct objfile *objfile) + dwarf_eh_frame_section = 0; + dwarf_ranges_section = 0; + dwarf_loc_section = 0; ++ dwarf_aranges_section = 0; + +- bfd_map_over_sections (objfile->obfd, dwarf2_locate_sections, NULL); ++ bfd_map_over_sections (objfile->obfd, dwarf2_locate_sections, &update_sizes); + return (dwarf_info_section != NULL && dwarf_abbrev_section != NULL); + } + +@@ -1149,51 +1181,61 @@ section_is_p (asection *sectp, const char *name) + in. */ + + static void +-dwarf2_locate_sections (bfd *abfd, asection *sectp, void *ignore_ptr) ++dwarf2_locate_sections (bfd *abfd, asection *sectp, void *user_data) + { ++ int update_sizes = * (int *) user_data; + if (section_is_p (sectp, INFO_SECTION)) + { +- dwarf2_per_objfile->info_size = bfd_get_section_size (sectp); ++ if (update_sizes) ++ dwarf2_per_objfile->info_size = bfd_get_section_size (sectp); + dwarf_info_section = sectp; + } + else if (section_is_p (sectp, ABBREV_SECTION)) + { +- dwarf2_per_objfile->abbrev_size = bfd_get_section_size (sectp); ++ if (update_sizes) ++ dwarf2_per_objfile->abbrev_size = bfd_get_section_size (sectp); + dwarf_abbrev_section = sectp; + } + else if (section_is_p (sectp, LINE_SECTION)) + { +- dwarf2_per_objfile->line_size = bfd_get_section_size (sectp); ++ if (update_sizes) ++ dwarf2_per_objfile->line_size = bfd_get_section_size (sectp); + dwarf_line_section = sectp; + } + else if (section_is_p (sectp, PUBNAMES_SECTION)) + { +- dwarf2_per_objfile->pubnames_size = bfd_get_section_size (sectp); ++ if (update_sizes) ++ dwarf2_per_objfile->pubnames_size = bfd_get_section_size (sectp); + dwarf_pubnames_section = sectp; + } + else if (section_is_p (sectp, ARANGES_SECTION)) + { +- dwarf2_per_objfile->aranges_size = bfd_get_section_size (sectp); ++ if (update_sizes) ++ dwarf2_per_objfile->aranges_size = bfd_get_section_size (sectp); + dwarf_aranges_section = sectp; + } + else if (section_is_p (sectp, LOC_SECTION)) + { +- dwarf2_per_objfile->loc_size = bfd_get_section_size (sectp); ++ if (update_sizes) ++ dwarf2_per_objfile->loc_size = bfd_get_section_size (sectp); + dwarf_loc_section = sectp; + } + else if (section_is_p (sectp, MACINFO_SECTION)) + { +- dwarf2_per_objfile->macinfo_size = bfd_get_section_size (sectp); ++ if (update_sizes) ++ dwarf2_per_objfile->macinfo_size = bfd_get_section_size (sectp); + dwarf_macinfo_section = sectp; + } + else if (section_is_p (sectp, STR_SECTION)) + { +- dwarf2_per_objfile->str_size = bfd_get_section_size (sectp); ++ if (update_sizes) ++ dwarf2_per_objfile->str_size = bfd_get_section_size (sectp); + dwarf_str_section = sectp; + } + else if (section_is_p (sectp, FRAME_SECTION)) + { +- dwarf2_per_objfile->frame_size = bfd_get_section_size (sectp); ++ if (update_sizes) ++ dwarf2_per_objfile->frame_size = bfd_get_section_size (sectp); + dwarf_frame_section = sectp; + } + else if (section_is_p (sectp, EH_FRAME_SECTION)) +@@ -1201,13 +1243,15 @@ dwarf2_locate_sections (bfd *abfd, asection *sectp, void *ignore_ptr) + flagword aflag = bfd_get_section_flags (ignore_abfd, sectp); + if (aflag & SEC_HAS_CONTENTS) + { +- dwarf2_per_objfile->eh_frame_size = bfd_get_section_size (sectp); ++ if (update_sizes) ++ dwarf2_per_objfile->eh_frame_size = bfd_get_section_size (sectp); + dwarf_eh_frame_section = sectp; + } + } + else if (section_is_p (sectp, RANGES_SECTION)) + { +- dwarf2_per_objfile->ranges_size = bfd_get_section_size (sectp); ++ if (update_sizes) ++ dwarf2_per_objfile->ranges_size = bfd_get_section_size (sectp); + dwarf_ranges_section = sectp; + } + +@@ -1250,6 +1294,86 @@ dwarf2_resize_section (asection *sectp, bfd_size_type new_size) + sectp->name); + } + ++/* A cleanup that frees an obstack. */ ++static void ++finalize_obstack (void *o) ++{ ++ struct obstack *ob = o; ++ obstack_free (o, 0); ++} ++ ++/* Read the .debug_aranges section and construct an address map. */ ++ ++void ++dwarf2_create_quick_addrmap (struct objfile *objfile) ++{ ++ char *aranges_buffer, *aranges_ptr; ++ bfd *abfd = objfile->obfd; ++ CORE_ADDR baseaddr; ++ struct cleanup *old; ++ struct obstack temp_obstack; ++ struct addrmap *mutable_map; ++ ++ if (!dwarf_aranges_section) ++ return; ++ ++ baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); ++ ++ aranges_buffer = dwarf2_read_section_1 (objfile, NULL, dwarf_aranges_section); ++ aranges_ptr = aranges_buffer; ++ old = make_cleanup (xfree, aranges_buffer); ++ ++ obstack_init (&temp_obstack); ++ make_cleanup (finalize_obstack, &temp_obstack); ++ mutable_map = addrmap_create_mutable (&temp_obstack); ++ ++ while ((aranges_ptr - aranges_buffer) < dwarf2_per_objfile->aranges_size) ++ { ++ struct comp_unit_head cu_header; ++ unsigned int bytes_read, segment_size, delta; ++ LONGEST info_offset; ++ struct dwarf2_cu cu; ++ ++ cu_header.initial_length_size = 0; ++ aranges_ptr = read_comp_unit_head (&cu_header, aranges_ptr, abfd); ++ ++ segment_size = read_1_byte (abfd, aranges_ptr); ++ aranges_ptr += 1; ++ ++ /* Align the pointer to twice the pointer size. I didn't see ++ this in the spec but it appears to be required. */ ++ delta = (aranges_ptr - aranges_buffer) % (2 * cu_header.addr_size); ++ delta = (2 * cu_header.addr_size - delta) % (2 * cu_header.addr_size); ++ aranges_ptr += delta; ++ ++ memset (&cu, 0, sizeof (cu)); ++ cu.header.addr_size = cu_header.addr_size; ++ ++ while (1) ++ { ++ CORE_ADDR address, length; ++ ++ address = read_address (abfd, aranges_ptr, &cu, &bytes_read); ++ aranges_ptr += bytes_read; ++ ++ length = read_address (abfd, aranges_ptr, &cu, &bytes_read); ++ aranges_ptr += bytes_read; ++ ++ if (address == 0 && length == 0) ++ break; ++ ++ address += baseaddr; ++ ++ addrmap_set_empty (mutable_map, address, address + length, objfile); ++ } ++ } ++ ++ objfile->quick_addrmap = addrmap_create_fixed (mutable_map, ++ &objfile->objfile_obstack); ++ do_cleanups (old); ++} ++ ++ + /* Build a partial symbol table. */ + + void +@@ -1453,22 +1577,24 @@ dwarf2_create_include_psymtab (char *name, struct partial_symtab *pst, + + /* Read the Line Number Program data and extract the list of files + included by the source file represented by PST. Build an include +- partial symtab for each of these included files. +- +- This procedure assumes that there *is* a Line Number Program in +- the given CU. Callers should check that PDI->HAS_STMT_LIST is set +- before calling this procedure. */ ++ partial symtab for each of these included files. */ + + static void + dwarf2_build_include_psymtabs (struct dwarf2_cu *cu, +- struct partial_die_info *pdi, ++ struct die_info *die, + struct partial_symtab *pst) + { + struct objfile *objfile = cu->objfile; + bfd *abfd = objfile->obfd; +- struct line_header *lh; ++ struct line_header *lh = NULL; ++ struct attribute *attr; + +- lh = dwarf_decode_line_header (pdi->line_offset, abfd, cu); ++ attr = dwarf2_attr (die, DW_AT_stmt_list, cu); ++ if (attr) ++ { ++ unsigned int line_offset = DW_UNSND (attr); ++ lh = dwarf_decode_line_header (line_offset, abfd, cu); ++ } + if (lh == NULL) + return; /* No linetable, so no includes. */ + +@@ -1477,6 +1603,36 @@ dwarf2_build_include_psymtabs (struct dwarf2_cu *cu, + free_line_header (lh); + } + ++/* Find the base address of the compilation unit for range lists and ++ location lists. It will normally be specified by DW_AT_low_pc. ++ In DWARF-3 draft 4, the base address could be overridden by ++ DW_AT_entry_pc. It's been removed, but GCC still uses this for ++ compilation units with discontinuous ranges. */ ++ ++static void ++dwarf2_find_base_address (struct die_info *die, struct dwarf2_cu *cu) ++{ ++ struct attribute *attr; ++ ++ cu->base_known = 0; ++ cu->base_address = 0; ++ ++ attr = dwarf2_attr (die, DW_AT_entry_pc, cu); ++ if (attr) ++ { ++ cu->base_address = DW_ADDR (attr); ++ cu->base_known = 1; ++ } ++ else ++ { ++ attr = dwarf2_attr (die, DW_AT_low_pc, cu); ++ if (attr) ++ { ++ cu->base_address = DW_ADDR (attr); ++ cu->base_known = 1; ++ } ++ } ++} + + /* Build the partial symbol table by doing a quick pass through the + .debug_info and .debug_abbrev sections. */ +@@ -1489,7 +1645,7 @@ dwarf2_build_psymtabs_hard (struct objfile *objfile, int mainline) + bfd *abfd = objfile->obfd; + gdb_byte *info_ptr; + gdb_byte *beg_of_comp_unit; +- struct partial_die_info comp_unit_die; ++ struct die_info *comp_unit_die; + struct partial_symtab *pst; + struct cleanup *back_to; + CORE_ADDR baseaddr; +@@ -1523,9 +1679,12 @@ dwarf2_build_psymtabs_hard (struct objfile *objfile, int mainline) + { + struct cleanup *back_to_inner; + struct dwarf2_cu cu; +- struct abbrev_info *abbrev; + unsigned int bytes_read; + struct dwarf2_per_cu_data *this_cu; ++ int has_children, has_pc_info; ++ struct attribute *attr; ++ const char *name; ++ CORE_ADDR best_lowpc, best_highpc; + + beg_of_comp_unit = info_ptr; + +@@ -1551,11 +1710,10 @@ dwarf2_build_psymtabs_hard (struct objfile *objfile, int mainline) + this_cu = dwarf2_find_comp_unit (cu.header.offset, objfile); + + /* Read the compilation unit die */ +- abbrev = peek_die_abbrev (info_ptr, &bytes_read, &cu); +- info_ptr = read_partial_die (&comp_unit_die, abbrev, bytes_read, +- abfd, info_ptr, &cu); ++ info_ptr = read_full_die (&comp_unit_die, abfd, info_ptr, &cu, ++ &has_children); + +- if (comp_unit_die.tag == DW_TAG_partial_unit) ++ if (comp_unit_die->tag == DW_TAG_partial_unit) + { + info_ptr = (beg_of_comp_unit + cu.header.length + + cu.header.initial_length_size); +@@ -1564,20 +1722,27 @@ dwarf2_build_psymtabs_hard (struct objfile *objfile, int mainline) + } + + /* Set the language we're debugging */ +- set_cu_language (comp_unit_die.language, &cu); ++ attr = dwarf2_attr (comp_unit_die, DW_AT_language, &cu); ++ if (attr != NULL) ++ set_cu_language (DW_UNSND (attr), &cu); ++ else ++ set_cu_language (language_minimal, &cu); + + /* Allocate a new partial symbol table structure */ +- pst = start_psymtab_common (objfile, objfile->section_offsets, +- comp_unit_die.name ? comp_unit_die.name : "", ++ attr = dwarf2_attr (comp_unit_die, DW_AT_name, &cu); ++ if (attr != NULL) ++ name = DW_STRING (attr); ++ else ++ name = ""; ++ pst = start_psymtab_common (objfile, objfile->section_offsets, name, + /* TEXTLOW and TEXTHIGH are set below. */ + 0, + objfile->global_psymbols.next, + objfile->static_psymbols.next); + +- if (comp_unit_die.dirname) +- pst->dirname = obsavestring (comp_unit_die.dirname, +- strlen (comp_unit_die.dirname), +- &objfile->objfile_obstack); ++ attr = dwarf2_attr (comp_unit_die, DW_AT_comp_dir, &cu); ++ if (attr != NULL) ++ pst->dirname = xstrdup (DW_STRING (attr)); + + pst->read_symtab_private = (char *) this_cu; + +@@ -1607,24 +1772,17 @@ dwarf2_build_psymtabs_hard (struct objfile *objfile, int mainline) + + /* Possibly set the default values of LOWPC and HIGHPC from + `DW_AT_ranges'. */ +- if (cu.has_ranges_offset) +- { +- if (dwarf2_ranges_read (cu.ranges_offset, &comp_unit_die.lowpc, +- &comp_unit_die.highpc, &cu, pst)) +- comp_unit_die.has_pc_info = 1; +- } +- else if (comp_unit_die.has_pc_info +- && comp_unit_die.lowpc < comp_unit_die.highpc) +- /* Store the contiguous range if it is not empty; it can be empty for +- CUs with no code. */ +- addrmap_set_empty (objfile->psymtabs_addrmap, +- comp_unit_die.lowpc + baseaddr, +- comp_unit_die.highpc + baseaddr - 1, pst); ++ has_pc_info = 0; ++ ++ if (dwarf2_get_pc_bounds (comp_unit_die, &best_lowpc, &best_highpc, &cu, ++ pst)) ++ has_pc_info = 1; ++ dwarf2_find_base_address (comp_unit_die, &cu); + + /* Check if comp unit has_children. + If so, read the rest of the partial symbols from this comp unit. + If not, there's no more debug_info for this comp unit. */ +- if (comp_unit_die.has_children) ++ if (has_children) + { + struct partial_die_info *first_die; + CORE_ADDR lowpc, highpc; +@@ -1634,8 +1792,7 @@ dwarf2_build_psymtabs_hard (struct objfile *objfile, int mainline) + + first_die = load_partial_dies (abfd, info_ptr, 1, &cu); + +- scan_partial_symbols (first_die, &lowpc, &highpc, +- ! comp_unit_die.has_pc_info, &cu); ++ scan_partial_symbols (first_die, &lowpc, &highpc, ! has_pc_info, &cu); + + /* If we didn't find a lowpc, set it to highpc to avoid + complaints from `maint check'. */ +@@ -1644,14 +1801,14 @@ dwarf2_build_psymtabs_hard (struct objfile *objfile, int mainline) + + /* If the compilation unit didn't have an explicit address range, + then use the information extracted from its child dies. */ +- if (! comp_unit_die.has_pc_info) ++ if (! has_pc_info) + { +- comp_unit_die.lowpc = lowpc; +- comp_unit_die.highpc = highpc; ++ best_lowpc = lowpc; ++ best_highpc = highpc; + } + } +- pst->textlow = comp_unit_die.lowpc + baseaddr; +- pst->texthigh = comp_unit_die.highpc + baseaddr; ++ pst->textlow = best_lowpc + baseaddr; ++ pst->texthigh = best_highpc + baseaddr; + + pst->n_global_syms = objfile->global_psymbols.next - + (objfile->global_psymbols.list + pst->globals_offset); +@@ -1667,12 +1824,9 @@ dwarf2_build_psymtabs_hard (struct objfile *objfile, int mainline) + info_ptr = beg_of_comp_unit + cu.header.length + + cu.header.initial_length_size; + +- if (comp_unit_die.has_stmt_list) +- { +- /* Get the list of files included in the current compilation unit, +- and build a psymtab for each of them. */ +- dwarf2_build_include_psymtabs (&cu, &comp_unit_die, pst); +- } ++ /* Get the list of files included in the current compilation unit, ++ and build a psymtab for each of them. */ ++ dwarf2_build_include_psymtabs (&cu, comp_unit_die, pst); + + do_cleanups (back_to_inner); + } +@@ -1690,11 +1844,12 @@ load_comp_unit (struct dwarf2_per_cu_data *this_cu, struct objfile *objfile) + { + bfd *abfd = objfile->obfd; + gdb_byte *info_ptr, *beg_of_comp_unit; +- struct partial_die_info comp_unit_die; ++ struct die_info *comp_unit_die; + struct dwarf2_cu *cu; +- struct abbrev_info *abbrev; + unsigned int bytes_read; + struct cleanup *back_to; ++ struct attribute *attr; ++ int has_children; + + info_ptr = dwarf2_per_objfile->info_buffer + this_cu->offset; + beg_of_comp_unit = info_ptr; +@@ -1716,12 +1871,15 @@ load_comp_unit (struct dwarf2_per_cu_data *this_cu, struct objfile *objfile) + back_to = make_cleanup (dwarf2_free_abbrev_table, cu); + + /* Read the compilation unit die. */ +- abbrev = peek_die_abbrev (info_ptr, &bytes_read, cu); +- info_ptr = read_partial_die (&comp_unit_die, abbrev, bytes_read, +- abfd, info_ptr, cu); ++ info_ptr = read_full_die (&comp_unit_die, abfd, info_ptr, cu, ++ &has_children); + + /* Set the language we're debugging. */ +- set_cu_language (comp_unit_die.language, cu); ++ attr = dwarf2_attr (comp_unit_die, DW_AT_language, cu); ++ if (attr) ++ set_cu_language (DW_UNSND (attr), cu); ++ else ++ set_cu_language (language_minimal, cu); + + /* Link this compilation unit into the compilation unit tree. */ + this_cu->cu = cu; +@@ -1731,7 +1889,7 @@ load_comp_unit (struct dwarf2_per_cu_data *this_cu, struct objfile *objfile) + /* Check if comp unit has_children. + If so, read the rest of the partial symbols from this comp unit. + If not, there's no more debug_info for this comp unit. */ +- if (comp_unit_die.has_children) ++ if (has_children) + load_partial_dies (abfd, info_ptr, 0, cu); + + do_cleanups (back_to); +@@ -1948,7 +2106,7 @@ partial_die_parent_scope (struct partial_die_info *pdi, + ignoring them. */ + complaint (&symfile_complaints, + _("unhandled containing DIE tag %d for DIE at %d"), +- parent->tag, pdi->offset); ++ parent->tag, real_pdi->offset); + parent->scope = grandparent_scope; + } + +@@ -1963,12 +2121,37 @@ partial_die_full_name (struct partial_die_info *pdi, + struct dwarf2_cu *cu) + { + char *parent_scope; ++ struct partial_die_info *real_pdi; + +- parent_scope = partial_die_parent_scope (pdi, cu); +- if (parent_scope == NULL) +- return NULL; +- else ++ /* We need to look at our parent DIE; if we have a DW_AT_specification, ++ then this means the parent of the specification DIE. ++ partial_die_parent_scope does this loop also, but we do it here ++ since we need to examine real_pdi->parent ourselves. */ ++ ++ real_pdi = pdi; ++ while (real_pdi->has_specification) ++ real_pdi = find_partial_die (real_pdi->spec_offset, cu); ++ ++ parent_scope = partial_die_parent_scope (real_pdi, cu); ++ if (parent_scope != NULL) + return typename_concat (NULL, parent_scope, pdi->name, cu); ++ ++ if (!cu->has_namespace_info && pdi->linkage_name ++ && !real_pdi->die_parent) ++ { ++ char *actual_scope ++ = language_class_name_from_physname (cu->language_defn, ++ pdi->linkage_name); ++ if (actual_scope != NULL) ++ { ++ char *actual_name = typename_concat (NULL, actual_scope, ++ pdi->name, cu); ++ xfree (actual_scope); ++ return actual_name; ++ } ++ } ++ ++ return NULL; + } + + static void +@@ -1984,7 +2167,9 @@ add_partial_symbol (struct partial_die_info *pdi, struct dwarf2_cu *cu) + + baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); + +- if (pdi_needs_namespace (pdi->tag)) ++ if (pdi->linkage_name != NULL) ++ actual_name = pdi->linkage_name; ++ else if (pdi_needs_namespace (pdi->tag)) + { + actual_name = partial_die_full_name (pdi, cu); + if (actual_name) +@@ -2133,9 +2318,8 @@ add_partial_symbol (struct partial_die_info *pdi, struct dwarf2_cu *cu) + if (cu->language == language_cplus + && cu->has_namespace_info == 0 + && psym != NULL +- && SYMBOL_CPLUS_DEMANGLED_NAME (psym) != NULL) +- cp_check_possible_namespace_symbols (SYMBOL_CPLUS_DEMANGLED_NAME (psym), +- objfile); ++ && pdi->linkage_name != NULL) ++ cp_check_possible_namespace_symbols (actual_name, objfile); + + if (built_actual_name) + xfree (actual_name); +@@ -2158,6 +2342,14 @@ pdi_needs_namespace (enum dwarf_tag tag) + case DW_TAG_union_type: + case DW_TAG_enumeration_type: + case DW_TAG_enumerator: ++ case DW_TAG_subprogram: ++ case DW_TAG_variable: ++ return 1; ++ case DW_TAG_member: ++ /* The only time we will encounter member variables in this ++ function is when we are creating a "linkage" name for them; ++ therefore they must be static members, so they do need a ++ class prefix. */ + return 1; + default: + return 0; +@@ -2290,11 +2482,11 @@ guess_structure_name (struct partial_die_info *struct_pdi, + + while (child_pdi != NULL) + { +- if (child_pdi->tag == DW_TAG_subprogram) ++ if (child_pdi->tag == DW_TAG_subprogram && child_pdi->linkage_name) + { + char *actual_class_name + = language_class_name_from_physname (cu->language_defn, +- child_pdi->name); ++ child_pdi->linkage_name); + if (actual_class_name != NULL) + { + struct_pdi->name +@@ -2741,7 +2933,6 @@ process_full_comp_unit (struct dwarf2_per_cu_data *per_cu) + CORE_ADDR lowpc, highpc; + struct symtab *symtab; + struct cleanup *back_to; +- struct attribute *attr; + CORE_ADDR baseaddr; + + baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); +@@ -2751,30 +2942,7 @@ process_full_comp_unit (struct dwarf2_per_cu_data *per_cu) + + cu->list_in_scope = &file_symbols; + +- /* Find the base address of the compilation unit for range lists and +- location lists. It will normally be specified by DW_AT_low_pc. +- In DWARF-3 draft 4, the base address could be overridden by +- DW_AT_entry_pc. It's been removed, but GCC still uses this for +- compilation units with discontinuous ranges. */ +- +- cu->base_known = 0; +- cu->base_address = 0; +- +- attr = dwarf2_attr (cu->dies, DW_AT_entry_pc, cu); +- if (attr) +- { +- cu->base_address = DW_ADDR (attr); +- cu->base_known = 1; +- } +- else +- { +- attr = dwarf2_attr (cu->dies, DW_AT_low_pc, cu); +- if (attr) +- { +- cu->base_address = DW_ADDR (attr); +- cu->base_known = 1; +- } +- } ++ dwarf2_find_base_address (cu->dies, cu); + + /* Do line number decoding in read_file_scope () */ + process_die (cu->dies, cu); +@@ -2805,6 +2973,7 @@ process_full_comp_unit (struct dwarf2_per_cu_data *per_cu) + static void + process_die (struct die_info *die, struct dwarf2_cu *cu) + { ++ + switch (die->tag) + { + case DW_TAG_padding: +@@ -2849,6 +3018,7 @@ process_die (struct die_info *die, struct dwarf2_cu *cu) + + case DW_TAG_base_type: + case DW_TAG_subrange_type: ++ case DW_TAG_typedef: + /* Add a typedef symbol for the type definition, if it has a + DW_AT_name. */ + new_symbol (die, read_type_die (die, cu), cu); +@@ -2867,14 +3037,12 @@ process_die (struct die_info *die, struct dwarf2_cu *cu) + break; + case DW_TAG_imported_declaration: + case DW_TAG_imported_module: +- /* FIXME: carlton/2002-10-16: Eventually, we should use the +- information contained in these. DW_TAG_imported_declaration +- dies shouldn't have children; DW_TAG_imported_module dies +- shouldn't in the C++ case, but conceivably could in the +- Fortran case. */ + processing_has_namespace_info = 1; +- complaint (&symfile_complaints, _("unsupported tag: '%s'"), +- dwarf_tag_name (die->tag)); ++ if (die->child != NULL && (die->tag == DW_TAG_imported_declaration ++ || cu->language != language_fortran)) ++ complaint (&symfile_complaints, _("Tag '%s' has unexpected children"), ++ dwarf_tag_name (die->tag)); ++ read_import_statement (die, cu); + break; + default: + new_symbol (die, NULL, cu); +@@ -2904,22 +3072,130 @@ dwarf2_full_name (struct die_info *die, struct dwarf2_cu *cu) + return name; + + /* If no prefix is necessary for this type of DIE, return the +- unqualified name. The other three tags listed could be handled +- in pdi_needs_namespace, but that requires broader changes. */ +- if (!pdi_needs_namespace (die->tag) +- && die->tag != DW_TAG_subprogram +- && die->tag != DW_TAG_variable +- && die->tag != DW_TAG_member) ++ unqualified name. */ ++ if (!pdi_needs_namespace (die->tag)) + return name; + + prefix = determine_prefix (die, cu); + if (*prefix != '\0') +- name = typename_concat (&cu->objfile->objfile_obstack, prefix, +- name, cu); ++ { ++ char *prefixed_name = typename_concat (NULL, prefix, name, cu); ++ buf = mem_fileopen (); ++ fputs_unfiltered (prefixed_name, buf); ++ xfree (prefixed_name); ++ } ++ ++ if (cu->language == language_cplus && die->tag == DW_TAG_subprogram) ++ { ++ struct type *type = read_type_die (die, cu); ++ ++ if (buf == NULL) ++ { ++ buf = mem_fileopen (); ++ fputs_unfiltered (name, buf); ++ } ++ ++ c_type_print_args (type, buf, 0); ++ } ++ ++ if (buf != NULL) ++ { ++ long length; ++ name = ui_file_obsavestring (buf, &cu->objfile->objfile_obstack, ++ &length); ++ ui_file_delete (buf); ++ } + + return name; + } + ++/* read the given die's decl_line number. Return -1 if in case of an error */ ++static int dwarf2_read_decl_line (struct die_info *die, struct dwarf2_cu *cu){ ++ struct attribute *line_attr; ++ ++ line_attr = dwarf2_attr (die, DW_AT_decl_line, cu); ++ if (line_attr){ ++ return DW_UNSND (line_attr); ++ } ++ ++ return -1; ++} ++ ++/* Read the import statement specified by the given die and record it. */ ++ ++static void ++read_import_statement (struct die_info *die, struct dwarf2_cu *cu) ++{ ++ struct attribute *import_attr; ++ struct die_info *imported_die; ++ const char *imported_name; ++ const char *imported_name_prefix; ++ char *canonical_name; ++ const char *import_alias; ++ const char *imported_declaration = ""; ++ const char *import_prefix; ++ ++ int line_number = -1; ++ ++ int is_anonymous = 0; ++ ++ import_attr = dwarf2_attr (die, DW_AT_import, cu); ++ if (import_attr == NULL) ++ { ++ complaint (&symfile_complaints, _("Tag '%s' has no DW_AT_import"), ++ dwarf_tag_name (die->tag)); ++ return; ++ } ++ ++ imported_die = follow_die_ref (die, import_attr, &cu); ++ imported_name = namespace_name (imported_die, &is_anonymous, cu); ++ if (imported_name == NULL) ++ { ++ /* C++ imports from std:: DW_TAG_base_type with no DW_AT_name - why? */ ++ return; ++ } ++ ++ /* Figure out the local name after import. */ ++ import_alias = dwarf2_name(die, cu); ++ if(import_alias == NULL){ ++ import_alias = ""; ++ } ++ ++ /* Determine the line number at which the import was made */ ++ line_number = dwarf2_read_decl_line(die, cu); ++ ++ /* Figure out where the statement is being imported to */ ++ import_prefix = determine_prefix (die, cu); ++ ++ /* ++ Figure out what the scope of the imported die is and prepend it ++ to the name of the imported die ++ */ ++ imported_name_prefix = determine_prefix (imported_die, cu); ++ ++ if(imported_die->tag != DW_TAG_namespace){ ++ imported_declaration = imported_name; ++ canonical_name = (char*)imported_name_prefix; ++ }else{ ++ if(strlen (imported_name_prefix) > 0){ ++ canonical_name = alloca (strlen (imported_name_prefix) + 2 + strlen (imported_name) + 1); ++ strcpy (canonical_name, imported_name_prefix); ++ strcat (canonical_name, "::"); ++ strcat (canonical_name, imported_name); ++ }else{ ++ canonical_name = alloca (strlen (imported_name) + 1); ++ strcpy (canonical_name, imported_name); ++ } ++ } ++ ++ using_directives = cp_add_using (import_prefix, ++ canonical_name, ++ import_alias, ++ imported_declaration, ++ line_number, ++ using_directives); ++} ++ + static void + initialize_cu_func_list (struct dwarf2_cu *cu) + { +@@ -3076,6 +3352,103 @@ add_to_cu_func_list (const char *name, CORE_ADDR lowpc, CORE_ADDR highpc, + cu->last_fn = thisfn; + } + ++static int ++unsigned_int_compar (const void *ap, const void *bp) ++{ ++ unsigned int a = *(unsigned int *) ap; ++ unsigned int b = *(unsigned int *) bp; ++ ++ return (a > b) - (b > a); ++} ++ ++static void explore_abstract_origin(struct die_info *die, struct dwarf2_cu *cu, unsigned* die_children_p){ ++ struct attribute *attr; ++ unsigned die_children = *die_children_p; ++ struct die_info *child_die; ++ ++ attr = dwarf2_attr (die, DW_AT_abstract_origin, cu); ++ ++ /* GCC currently uses DW_AT_specification to indicate die inheritence ++ in the case of import statements. The following is to accommodate that */ ++ if(!attr){ ++ attr = dwarf2_attr (die, DW_AT_specification, cu); ++ } ++ ++ if (attr) ++ { ++ /* For the list of CHILD_DIEs. */ ++ unsigned *offsets; ++ unsigned *offsets_end, *offsetp; ++ struct die_info *origin_die, *origin_child_die; ++ struct cleanup *cleanups; ++ ++ origin_die = follow_die_ref (die, attr, &cu); ++ if (die->tag != origin_die->tag) ++ complaint (&symfile_complaints, ++ _("DIE 0x%x and its abstract origin 0x%x have different " ++ "tags"), ++ die->offset, origin_die->offset); ++ ++ offsets = xmalloc (sizeof (*offsets) * die_children); ++ cleanups = make_cleanup (xfree, offsets); ++ ++ offsets_end = offsets; ++ child_die = die->child; ++ while (child_die && child_die->tag) ++ { ++ attr = dwarf2_attr (child_die, DW_AT_abstract_origin, cu); ++ if (!attr) ++ complaint (&symfile_complaints, ++ _("Child DIE 0x%x of DIE 0x%x has missing " ++ "DW_AT_abstract_origin"), ++ child_die->offset, die->offset); ++ else ++ { ++ struct die_info *child_origin_die; ++ ++ child_origin_die = follow_die_ref (child_die, attr, &cu); ++ if (child_die->tag != child_origin_die->tag) ++ complaint (&symfile_complaints, ++ _("Child DIE 0x%x and its abstract origin 0x%x have " ++ "different tags"), ++ child_die->offset, child_origin_die->offset); ++ *offsets_end++ = child_origin_die->offset; ++ } ++ child_die = sibling_die (child_die); ++ } ++ qsort (offsets, offsets_end - offsets, sizeof (*offsets), ++ unsigned_int_compar); ++ /* Disabled as excessively expensive - check if we may ever complain. */ ++ if (0) ++ { ++ for (offsetp = offsets + 1; offsetp < offsets_end; offsetp++) ++ if (offsetp[-1] == *offsetp) ++ complaint (&symfile_complaints, ++ _("Child DIEs of DIE 0x%x duplicitly abstract-origin " ++ "referenced DIE 0x%x"), ++ die->offset, *offsetp); ++ } ++ ++ offsetp = offsets; ++ origin_child_die = origin_die->child; ++ while (origin_child_die && origin_child_die->tag) ++ { ++ /* Is origin_child_die referenced by any of the DIE children? */ ++ while (offsetp < offsets_end && *offsetp < origin_child_die->offset) ++ offsetp++; ++ if (offsetp >= offsets_end || *offsetp > origin_child_die->offset) ++ { ++ /* Found that origin_child_die is really not referenced. */ ++ process_die (origin_child_die, cu); ++ } ++ origin_child_die = sibling_die (origin_child_die); ++ } ++ ++ do_cleanups (cleanups); ++ } ++ ++} ++ + static void + read_func_scope (struct die_info *die, struct dwarf2_cu *cu) + { +@@ -3088,16 +3461,27 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu) + char *name; + CORE_ADDR baseaddr; + struct block *block; ++ unsigned die_children = 0; + + baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); + +- name = dwarf2_linkage_name (die, cu); ++ name = dwarf2_name (die, cu); + + /* Ignore functions with missing or empty names and functions with + missing or invalid low and high pc attributes. */ +- if (name == NULL || !dwarf2_get_pc_bounds (die, &lowpc, &highpc, cu)) ++ if (name == NULL || !dwarf2_get_pc_bounds (die, &lowpc, &highpc, cu, NULL)){ ++ /* explore abstract origins if present. They might contain useful information ++ such as import statements. */ ++ child_die = die->child; ++ while (child_die && child_die->tag) ++ { ++ child_die = sibling_die (child_die); ++ die_children++; ++ } ++ explore_abstract_origin(die, cu, &die_children); + return; +- ++ } ++ + lowpc += baseaddr; + highpc += baseaddr; + +@@ -3124,16 +3508,91 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu) + + cu->list_in_scope = &local_symbols; + +- if (die->child != NULL) ++ child_die = die->child; ++ die_children = 0; ++ while (child_die && child_die->tag) + { ++ process_die (child_die, cu); ++ child_die = sibling_die (child_die); ++ die_children++; ++ } ++ ++ attr = dwarf2_attr (die, DW_AT_abstract_origin, cu); ++ if (attr) ++ { ++ /* For the list of CHILD_DIEs. */ ++ unsigned *offsets; ++ unsigned *offsets_end, *offsetp; ++ struct die_info *origin_die, *origin_child_die; ++ struct cleanup *cleanups; ++ ++ origin_die = follow_die_ref (die, attr, &cu); ++ if (die->tag != origin_die->tag) ++ complaint (&symfile_complaints, ++ _("DIE 0x%x and its abstract origin 0x%x have different " ++ "tags"), ++ die->offset, origin_die->offset); ++ ++ offsets = xmalloc (sizeof (*offsets) * die_children); ++ cleanups = make_cleanup (xfree, offsets); ++ ++ offsets_end = offsets; + child_die = die->child; + while (child_die && child_die->tag) + { +- process_die (child_die, cu); ++ attr = dwarf2_attr (child_die, DW_AT_abstract_origin, cu); ++ if (!attr) ++ complaint (&symfile_complaints, ++ _("Child DIE 0x%x of DIE 0x%x has missing " ++ "DW_AT_abstract_origin"), ++ child_die->offset, die->offset); ++ else ++ { ++ struct die_info *child_origin_die; ++ ++ child_origin_die = follow_die_ref (child_die, attr, &cu); ++ if (child_die->tag != child_origin_die->tag) ++ complaint (&symfile_complaints, ++ _("Child DIE 0x%x and its abstract origin 0x%x have " ++ "different tags"), ++ child_die->offset, child_origin_die->offset); ++ *offsets_end++ = child_origin_die->offset; ++ } + child_die = sibling_die (child_die); + } ++ qsort (offsets, offsets_end - offsets, sizeof (*offsets), ++ unsigned_int_compar); ++ /* Disabled as excessively expensive - check if we may ever complain. */ ++ if (0) ++ { ++ for (offsetp = offsets + 1; offsetp < offsets_end; offsetp++) ++ if (offsetp[-1] == *offsetp) ++ complaint (&symfile_complaints, ++ _("Child DIEs of DIE 0x%x duplicitly abstract-origin " ++ "referenced DIE 0x%x"), ++ die->offset, *offsetp); ++ } ++ ++ offsetp = offsets; ++ origin_child_die = origin_die->child; ++ while (origin_child_die && origin_child_die->tag) ++ { ++ /* Is origin_child_die referenced by any of the DIE children? */ ++ while (offsetp < offsets_end && *offsetp < origin_child_die->offset) ++ offsetp++; ++ if (offsetp >= offsets_end || *offsetp > origin_child_die->offset) ++ { ++ /* Found that origin_child_die is really not referenced. */ ++ process_die (origin_child_die, cu); ++ } ++ origin_child_die = sibling_die (origin_child_die); ++ } ++ ++ do_cleanups (cleanups); + } + ++ explore_abstract_origin(die, cu, &die_children); ++ + new = pop_context (); + /* Make a block for the local symbols within. */ + block = finish_block (new->name, &local_symbols, new->old_blocks, +@@ -3154,6 +3613,7 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu) + back to building a containing block's symbol lists. */ + local_symbols = new->locals; + param_symbols = new->params; ++ using_directives = new->using_directives; + + /* If we've finished processing a top-level function, subsequent + symbols go in the file symbol list. */ +@@ -3180,7 +3640,7 @@ read_lexical_block_scope (struct die_info *die, struct dwarf2_cu *cu) + as multiple lexical blocks? Handling children in a sane way would + be nasty. Might be easier to properly extend generic blocks to + describe ranges. */ +- if (!dwarf2_get_pc_bounds (die, &lowpc, &highpc, cu)) ++ if (!dwarf2_get_pc_bounds (die, &lowpc, &highpc, cu, NULL)) + return; + lowpc += baseaddr; + highpc += baseaddr; +@@ -3216,6 +3676,7 @@ read_lexical_block_scope (struct die_info *die, struct dwarf2_cu *cu) + dwarf2_record_block_ranges (die, block, baseaddr, cu); + } + local_symbols = new->locals; ++ using_directives = new->using_directives; + } + + /* Get low and high pc attributes from DW_AT_ranges attribute value OFFSET. +@@ -3351,7 +3812,8 @@ dwarf2_ranges_read (unsigned offset, CORE_ADDR *low_return, + discontinuous, i.e. derived from DW_AT_ranges information. */ + static int + dwarf2_get_pc_bounds (struct die_info *die, CORE_ADDR *lowpc, +- CORE_ADDR *highpc, struct dwarf2_cu *cu) ++ CORE_ADDR *highpc, struct dwarf2_cu *cu, ++ struct partial_symtab *pst) + { + struct attribute *attr; + CORE_ADDR low = 0; +@@ -3379,7 +3841,7 @@ dwarf2_get_pc_bounds (struct die_info *die, CORE_ADDR *lowpc, + { + /* Value of the DW_AT_ranges attribute is the offset in the + .debug_ranges section. */ +- if (!dwarf2_ranges_read (DW_UNSND (attr), &low, &high, cu, NULL)) ++ if (!dwarf2_ranges_read (DW_UNSND (attr), &low, &high, cu, pst)) + return 0; + /* Found discontinuous range of addresses. */ + ret = -1; +@@ -3418,7 +3880,7 @@ dwarf2_get_subprogram_pc_bounds (struct die_info *die, + CORE_ADDR low, high; + struct die_info *child = die->child; + +- if (dwarf2_get_pc_bounds (die, &low, &high, cu)) ++ if (dwarf2_get_pc_bounds (die, &low, &high, cu, NULL)) + { + *lowpc = min (*lowpc, low); + *highpc = max (*highpc, high); +@@ -3455,7 +3917,7 @@ get_scope_pc_bounds (struct die_info *die, + CORE_ADDR best_high = (CORE_ADDR) 0; + CORE_ADDR current_low, current_high; + +- if (dwarf2_get_pc_bounds (die, ¤t_low, ¤t_high, cu)) ++ if (dwarf2_get_pc_bounds (die, ¤t_low, ¤t_high, cu, NULL)) + { + best_low = current_low; + best_high = current_high; +@@ -3750,8 +4212,14 @@ dwarf2_add_field (struct field_info *fip, struct die_info *die, + if (fieldname == NULL) + return; + +- /* Get physical name. */ ++ /* Get physical name. We prefer the linkage name if one was specified, ++ because this lets GDB find a non-debugging version of the symbol. ++ Otherwise construct the full name from type information. Ideally, ++ when GDB supports canonicalization of C++ symbol names, we will not ++ need the linkage name for anything. */ + physname = dwarf2_linkage_name (die, cu); ++ if (physname == NULL) ++ physname = (char *) dwarf2_full_name (die, cu); + + /* The name is already allocated along with this objfile, so we don't + need to duplicate it for the type. */ +@@ -3881,8 +4349,14 @@ dwarf2_add_member_fn (struct field_info *fip, struct die_info *die, + if (fieldname == NULL) + return; + +- /* Get the mangled name. */ ++ /* Get physical name. We prefer the linkage name if one was specified, ++ because this lets GDB find a non-debugging version of the symbol. ++ Otherwise construct the full name from type information. Ideally, ++ when GDB supports canonicalization of C++ symbol names, we will not ++ need the linkage name for anything. */ + physname = dwarf2_linkage_name (die, cu); ++ if (physname == NULL) ++ physname = (char *) dwarf2_full_name (die, cu); + + /* Look up member function name in fieldlist. */ + for (i = 0; i < fip->nfnfields; i++) +@@ -3926,7 +4400,7 @@ dwarf2_add_member_fn (struct field_info *fip, struct die_info *die, + /* The name is already allocated along with this objfile, so we don't + need to duplicate it for the type. */ + fnp->physname = physname ? physname : ""; +- fnp->type = alloc_type (objfile); ++ fnp->type = alloc_type (objfile, NULL); + this_type = read_type_die (die, cu); + if (this_type && TYPE_CODE (this_type) == TYPE_CODE_FUNC) + { +@@ -4110,7 +4584,7 @@ quirk_gcc_member_function_pointer (struct die_info *die, struct dwarf2_cu *cu) + return NULL; + + domain_type = TYPE_TARGET_TYPE (TYPE_FIELD_TYPE (pfn_type, 0)); +- type = alloc_type (objfile); ++ type = alloc_type (objfile, NULL); + smash_to_method_type (type, domain_type, TYPE_TARGET_TYPE (pfn_type), + TYPE_FIELDS (pfn_type), TYPE_NFIELDS (pfn_type), + TYPE_VARARGS (pfn_type)); +@@ -4147,7 +4621,7 @@ read_structure_type (struct die_info *die, struct dwarf2_cu *cu) + if (type) + return type; + +- type = alloc_type (objfile); ++ type = alloc_type (objfile, NULL); + INIT_CPLUS_SPECIFIC (type); + name = dwarf2_name (die, cu); + if (name != NULL) +@@ -4360,7 +4834,7 @@ read_enumeration_type (struct die_info *die, struct dwarf2_cu *cu) + struct attribute *attr; + const char *name; + +- type = alloc_type (objfile); ++ type = alloc_type (objfile, NULL); + + TYPE_CODE (type) = TYPE_CODE_ENUM; + name = dwarf2_full_name (die, cu); +@@ -4410,10 +4884,15 @@ determine_class_name (struct die_info *die, struct dwarf2_cu *cu) + { + if (child->tag == DW_TAG_subprogram) + { +- char *phys_prefix ++ char *phys_prefix; ++ char *linkage_name = dwarf2_linkage_name (child, cu); ++ ++ if (linkage_name == NULL) ++ continue; ++ ++ phys_prefix + = language_class_name_from_physname (cu->language_defn, +- dwarf2_linkage_name +- (child, cu)); ++ linkage_name); + + if (phys_prefix != NULL) + { +@@ -4510,6 +4989,29 @@ process_enumeration_scope (struct die_info *die, struct dwarf2_cu *cu) + new_symbol (die, this_type, cu); + } + ++/* Create a new array dimension referencing its target type TYPE. ++ ++ Multidimensional arrays are internally represented as a stack of ++ singledimensional arrays being referenced by their TYPE_TARGET_TYPE. */ ++ ++static struct type * ++create_single_array_dimension (struct type *type, struct type *range_type, ++ struct die_info *die, struct dwarf2_cu *cu) ++{ ++ type = create_array_type (NULL, type, range_type); ++ ++ /* These generic type attributes need to be fetched by ++ evaluate_subexp_standard 's call of ++ value_subscripted_rvalue only for the innermost array type. */ ++ fetch_die_type_attrs (die, type, cu); ++ ++ /* These generic type attributes are checked for allocated/associated ++ validity while accessing FIELD_LOC_KIND_DWARF_BLOCK. */ ++ fetch_die_type_attrs (die, range_type, cu); ++ ++ return type; ++} ++ + /* Extract all information from a DW_TAG_array_type DIE and put it in + the DIE's type field. For now, this only handles one dimensional + arrays. */ +@@ -4523,7 +5025,7 @@ read_array_type (struct die_info *die, struct dwarf2_cu *cu) + struct type *element_type, *range_type, *index_type; + struct type **range_types = NULL; + struct attribute *attr; +- int ndim = 0; ++ int ndim = 0, i; + struct cleanup *back_to; + char *name; + +@@ -4570,16 +5072,11 @@ read_array_type (struct die_info *die, struct dwarf2_cu *cu) + type = element_type; + + if (read_array_order (die, cu) == DW_ORD_col_major) +- { +- int i = 0; +- while (i < ndim) +- type = create_array_type (NULL, type, range_types[i++]); +- } +- else +- { +- while (ndim-- > 0) +- type = create_array_type (NULL, type, range_types[ndim]); +- } ++ for (i = 0; i < ndim; i++) ++ type = create_single_array_dimension (type, range_types[i], die, cu); ++ else /* (read_array_order (die, cu) == DW_ORD_row_major) */ ++ for (i = ndim - 1; i >= 0; i--) ++ type = create_single_array_dimension (type, range_types[i], die, cu); + + /* Understand Dwarf2 support for vector types (like they occur on + the PowerPC w/ AltiVec). Gcc just adds another attribute to the +@@ -4646,12 +5143,14 @@ read_set_type (struct die_info *die, struct dwarf2_cu *cu) + return set_die_type (die, set_type, cu); + } + +-/* First cut: install each common block member as a global variable. */ ++/* Create appropriate locally-scoped variables for all the DW_TAG_common_block ++ entries. Create also TYPE_CODE_STRUCT listing all such variables to be ++ available for `info common'. COMMON_BLOCK_DOMAIN is used to sepate the ++ common blocks name namespace from regular variable names. */ + + static void + read_common_block (struct die_info *die, struct dwarf2_cu *cu) + { +- struct die_info *child_die; + struct attribute *attr; + struct symbol *sym; + CORE_ADDR base = (CORE_ADDR) 0; +@@ -4676,10 +5175,40 @@ read_common_block (struct die_info *die, struct dwarf2_cu *cu) + } + if (die->child != NULL) + { ++ struct objfile *objfile = cu->objfile; ++ struct die_info *child_die; ++ struct type *type; ++ struct field *field; ++ char *name; ++ struct symbol *sym; ++ ++ type = alloc_type (objfile, NULL); ++ TYPE_CODE (type) = TYPE_CODE_STRUCT; ++ /* Artificial type to be used only by `info common'. */ ++ TYPE_NAME (type) = ""; ++ + child_die = die->child; + while (child_die && child_die->tag) + { ++ TYPE_NFIELDS (type)++; ++ child_die = sibling_die (child_die); ++ } ++ ++ TYPE_FIELDS (type) = obstack_alloc (&objfile->objfile_obstack, ++ sizeof (*TYPE_FIELDS (type)) ++ * TYPE_NFIELDS (type)); ++ memset (TYPE_FIELDS (type), 0, sizeof (*TYPE_FIELDS (type)) ++ * TYPE_NFIELDS (type)); ++ ++ field = TYPE_FIELDS (type); ++ child_die = die->child; ++ while (child_die && child_die->tag) ++ { ++ /* Create the symbol in the DW_TAG_common_block block in the current ++ symbol scope. */ + sym = new_symbol (child_die, NULL, cu); ++ ++ /* Undocumented in DWARF3, when it can be present? */ + attr = dwarf2_attr (child_die, DW_AT_data_member_location, cu); + if (attr) + { +@@ -4687,8 +5216,25 @@ read_common_block (struct die_info *die, struct dwarf2_cu *cu) + base + decode_locdesc (DW_BLOCK (attr), cu); + add_symbol_to_list (sym, &global_symbols); + } ++ ++ if (SYMBOL_CLASS (sym) == LOC_STATIC) ++ SET_FIELD_PHYSADDR (*field, SYMBOL_VALUE_ADDRESS (sym)); ++ else ++ SET_FIELD_PHYSNAME (*field, SYMBOL_LINKAGE_NAME (sym)); ++ FIELD_TYPE (*field) = SYMBOL_TYPE (sym); ++ FIELD_NAME (*field) = SYMBOL_NATURAL_NAME (sym); ++ field++; + child_die = sibling_die (child_die); + } ++ ++ /* TYPE_LENGTH (type) is left 0 - it is only a virtual structure even ++ with no consecutive address space. */ ++ ++ sym = new_symbol (die, type, cu); ++ /* SYMBOL_VALUE_ADDRESS never gets used as all its fields are static. */ ++ SYMBOL_VALUE_ADDRESS (sym) = base; ++ ++ set_die_type (die, type, cu); + } + } + +@@ -4756,9 +5302,7 @@ read_namespace (struct die_info *die, struct dwarf2_cu *cu) + if (is_anonymous) + { + const char *previous_prefix = determine_prefix (die, cu); +- cp_add_using_directive (TYPE_NAME (type), +- strlen (previous_prefix), +- strlen (TYPE_NAME (type))); ++ cp_add_using_directive (previous_prefix, TYPE_NAME (type), "", "", dwarf2_read_decl_line(die, cu)); + } + } + +@@ -4951,29 +5495,95 @@ read_tag_string_type (struct die_info *die, struct dwarf2_cu *cu) + struct objfile *objfile = cu->objfile; + struct type *type, *range_type, *index_type, *char_type; + struct attribute *attr; +- unsigned int length; ++ int length; ++ ++ index_type = builtin_type_int32; ++ /* RANGE_TYPE is allocated from OBJFILE, not OBJFILE_INTERNAL. */ ++ range_type = alloc_type (objfile, index_type); ++ /* LOW_BOUND and HIGH_BOUND are set for real below. */ ++ range_type = create_range_type (range_type, index_type, 0, -1); ++ ++ /* C/C++ should probably have the low bound 0 but C/C++ does not use ++ DW_TAG_string_type. */ ++ TYPE_LOW_BOUND (range_type) = 1; + + attr = dwarf2_attr (die, DW_AT_string_length, cu); +- if (attr) +- { +- length = DW_UNSND (attr); +- } +- else +- { +- /* check for the DW_AT_byte_size attribute */ ++ switch (dwarf2_get_attr_constant_value (attr, &length)) ++ { ++ case dwarf2_attr_const: ++ /* We currently do not support a constant address where the location ++ should be read from - DWARF2_ATTR_BLOCK is expected instead. See ++ DWARF for the DW_AT_STRING_LENGTH vs. DW_AT_BYTE_SIZE difference. */ ++ /* PASSTHRU */ ++ case dwarf2_attr_unknown: + attr = dwarf2_attr (die, DW_AT_byte_size, cu); +- if (attr) +- { +- length = DW_UNSND (attr); +- } +- else +- { +- length = 1; +- } ++ switch (dwarf2_get_attr_constant_value (attr, &length)) ++ { ++ case dwarf2_attr_unknown: ++ length = 1; ++ /* PASSTHRU */ ++ case dwarf2_attr_const: ++ TYPE_HIGH_BOUND (range_type) = length; ++ break; ++ case dwarf2_attr_block: ++ TYPE_RANGE_BOUND_SET_DWARF_BLOCK (range_type, 1); ++ TYPE_FIELD_DWARF_BLOCK (range_type, 1) = ++ dwarf2_attr_to_locexpr_baton (attr, cu); ++ TYPE_DYNAMIC (range_type) = 1; ++ break; ++ } ++ break; ++ case dwarf2_attr_block: ++ /* Security check for a size overflow. */ ++ if (DW_BLOCK (attr)->size + 2 < DW_BLOCK (attr)->size) ++ { ++ TYPE_HIGH_BOUND (range_type) = 1; ++ break; ++ } ++ /* Extend the DWARF block by a new DW_OP_deref/DW_OP_deref_size ++ instruction as DW_AT_string_length specifies the length location, not ++ its value. */ ++ { ++ struct dwarf2_locexpr_baton *length_baton; ++ struct attribute *size_attr; ++ ++ length_baton = obstack_alloc (&cu->comp_unit_obstack, ++ sizeof (*length_baton)); ++ length_baton->per_cu = cu->per_cu; ++ length_baton->data = obstack_alloc (&cu->comp_unit_obstack, ++ DW_BLOCK (attr)->size + 2); ++ memcpy (length_baton->data, DW_BLOCK (attr)->data, ++ DW_BLOCK (attr)->size); ++ ++ /* DW_AT_BYTE_SIZE existing together with DW_AT_STRING_LENGTH specifies ++ the size of an integer to fetch. */ ++ ++ size_attr = dwarf2_attr (die, DW_AT_byte_size, cu); ++ if (size_attr) ++ { ++ length_baton->size = DW_BLOCK (attr)->size + 2; ++ length_baton->data[DW_BLOCK (attr)->size] = DW_OP_deref_size; ++ length_baton->data[DW_BLOCK (attr)->size + 1] ++ = DW_UNSND (size_attr); ++ if (length_baton->data[DW_BLOCK (attr)->size + 1] ++ != DW_UNSND (size_attr)) ++ complaint (&symfile_complaints, ++ _("DW_AT_string_length's DW_AT_byte_size integer " ++ "exceeds the byte size storage")); ++ } ++ else ++ { ++ length_baton->size = DW_BLOCK (attr)->size + 1; ++ length_baton->data[DW_BLOCK (attr)->size] = DW_OP_deref; ++ } ++ ++ TYPE_RANGE_BOUND_SET_DWARF_BLOCK (range_type, 1); ++ TYPE_FIELD_DWARF_BLOCK (range_type, 1) = length_baton; ++ TYPE_DYNAMIC (range_type) = 1; ++ } ++ break; + } + +- index_type = builtin_type_int32; +- range_type = create_range_type (NULL, index_type, 1, length); + type = create_string_type (NULL, range_type); + + return set_die_type (die, type, cu); +@@ -5067,7 +5677,6 @@ static struct type * + read_typedef (struct die_info *die, struct dwarf2_cu *cu) + { + struct objfile *objfile = cu->objfile; +- struct attribute *attr; + const char *name = NULL; + struct type *this_type; + +@@ -5175,8 +5784,8 @@ read_subrange_type (struct die_info *die, struct dwarf2_cu *cu) + struct type *base_type; + struct type *range_type; + struct attribute *attr; +- int low = 0; +- int high = -1; ++ int low, high, byte_stride_int; ++ enum dwarf2_get_attr_constant_value high_type; + char *name; + + base_type = die_type (die, cu); +@@ -5189,42 +5798,90 @@ read_subrange_type (struct die_info *die, struct dwarf2_cu *cu) + 0, NULL, cu->objfile); + } + +- if (cu->language == language_fortran) +- { +- /* FORTRAN implies a lower bound of 1, if not given. */ +- low = 1; +- } ++ /* LOW_BOUND and HIGH_BOUND are set for real below. */ ++ range_type = create_range_type (NULL, base_type, 0, -1); + +- /* FIXME: For variable sized arrays either of these could be +- a variable rather than a constant value. We'll allow it, +- but we don't know how to handle it. */ + attr = dwarf2_attr (die, DW_AT_lower_bound, cu); +- if (attr) +- low = dwarf2_get_attr_constant_value (attr, 0); ++ switch (dwarf2_get_attr_constant_value (attr, &low)) ++ { ++ case dwarf2_attr_unknown: ++ if (cu->language == language_fortran) ++ { ++ /* FORTRAN implies a lower bound of 1, if not given. */ ++ low = 1; ++ } ++ else ++ { ++ /* According to DWARF we should assume the value 0 only for ++ LANGUAGE_C and LANGUAGE_CPLUS. */ ++ low = 0; ++ } ++ /* PASSTHRU */ ++ case dwarf2_attr_const: ++ TYPE_LOW_BOUND (range_type) = low; ++ if (low >= 0) ++ TYPE_UNSIGNED (range_type) = 1; ++ break; ++ case dwarf2_attr_block: ++ TYPE_RANGE_BOUND_SET_DWARF_BLOCK (range_type, 0); ++ TYPE_FIELD_DWARF_BLOCK (range_type, 0) = dwarf2_attr_to_locexpr_baton ++ (attr, cu); ++ TYPE_DYNAMIC (range_type) = 1; ++ /* For setting a default if DW_AT_UPPER_BOUND would be missing. */ ++ low = 0; ++ break; ++ } + + attr = dwarf2_attr (die, DW_AT_upper_bound, cu); +- if (attr) +- { +- if (attr->form == DW_FORM_block1) +- { +- /* GCC encodes arrays with unspecified or dynamic length +- with a DW_FORM_block1 attribute. +- FIXME: GDB does not yet know how to handle dynamic +- arrays properly, treat them as arrays with unspecified +- length for now. +- +- FIXME: jimb/2003-09-22: GDB does not really know +- how to handle arrays of unspecified length +- either; we just represent them as zero-length +- arrays. Choose an appropriate upper bound given +- the lower bound we've computed above. */ +- high = low - 1; +- } +- else +- high = dwarf2_get_attr_constant_value (attr, 1); ++ high_type = dwarf2_get_attr_constant_value (attr, &high); ++ if (high_type == dwarf2_attr_unknown) ++ { ++ attr = dwarf2_attr (die, DW_AT_count, cu); ++ high_type = dwarf2_get_attr_constant_value (attr, &high); ++ /* It does not hurt but it is needlessly ineffective in check_typedef. */ ++ if (high_type != dwarf2_attr_unknown) ++ { ++ TYPE_RANGE_HIGH_BOUND_IS_COUNT (range_type) = 1; ++ TYPE_DYNAMIC (range_type) = 1; ++ } ++ /* Pass it now as the regular DW_AT_upper_bound. */ ++ } ++ switch (high_type) ++ { ++ case dwarf2_attr_unknown: ++ TYPE_RANGE_UPPER_BOUND_IS_UNDEFINED (range_type) = 1; ++ high = low - 1; ++ /* PASSTHRU */ ++ case dwarf2_attr_const: ++ TYPE_HIGH_BOUND (range_type) = high; ++ break; ++ case dwarf2_attr_block: ++ TYPE_RANGE_BOUND_SET_DWARF_BLOCK (range_type, 1); ++ TYPE_FIELD_DWARF_BLOCK (range_type, 1) = dwarf2_attr_to_locexpr_baton ++ (attr, cu); ++ TYPE_DYNAMIC (range_type) = 1; ++ break; + } + +- range_type = create_range_type (NULL, base_type, low, high); ++ /* DW_AT_bit_stride is currently unsupported as we count in bytes. */ ++ attr = dwarf2_attr (die, DW_AT_byte_stride, cu); ++ switch (dwarf2_get_attr_constant_value (attr, &byte_stride_int)) ++ { ++ case dwarf2_attr_unknown: ++ break; ++ case dwarf2_attr_const: ++ if (byte_stride_int == 0) ++ complaint (&symfile_complaints, ++ _("Found DW_AT_byte_stride with unsupported value 0")); ++ TYPE_BYTE_STRIDE (range_type) = byte_stride_int; ++ break; ++ case dwarf2_attr_block: ++ TYPE_RANGE_BOUND_SET_DWARF_BLOCK (range_type, 2); ++ TYPE_FIELD_DWARF_BLOCK (range_type, 2) = dwarf2_attr_to_locexpr_baton ++ (attr, cu); ++ TYPE_DYNAMIC (range_type) = 1; ++ break; ++ } + + name = dwarf2_name (die, cu); + if (name) +@@ -5386,10 +6043,13 @@ read_die_and_siblings (gdb_byte *info_ptr, bfd *abfd, + } + + /* Decompress a section that was compressed using zlib. Store the +- decompressed buffer, and its size, in OUTBUF and OUTSIZE. */ ++ decompressed buffer, and its size, in OUTBUF and OUTSIZE. The ++ result is allocated on OBSTACK; if OBSTACK is NULL, xmalloc is ++ used. */ + + static void +-zlib_decompress_section (struct objfile *objfile, asection *sectp, ++zlib_decompress_section (struct objfile *objfile, struct obstack *obstack, ++ asection *sectp, + gdb_byte **outbuf, bfd_size_type *outsize) + { + bfd *abfd = objfile->obfd; +@@ -5405,6 +6065,7 @@ zlib_decompress_section (struct objfile *objfile, asection *sectp, + z_stream strm; + int rc; + int header_size = 12; ++ struct cleanup *old = NULL; + + if (bfd_seek (abfd, sectp->filepos, SEEK_SET) != 0 + || bfd_bread (compressed_buffer, compressed_size, abfd) != compressed_size) +@@ -5434,8 +6095,13 @@ zlib_decompress_section (struct objfile *objfile, asection *sectp, + strm.avail_in = compressed_size - header_size; + strm.next_in = (Bytef*) compressed_buffer + header_size; + strm.avail_out = uncompressed_size; +- uncompressed_buffer = obstack_alloc (&objfile->objfile_obstack, +- uncompressed_size); ++ if (obstack) ++ uncompressed_buffer = obstack_alloc (obstack, uncompressed_size); ++ else ++ { ++ uncompressed_buffer = xmalloc (uncompressed_size); ++ old = make_cleanup (xfree, uncompressed_buffer); ++ } + rc = inflateInit (&strm); + while (strm.avail_in > 0) + { +@@ -5456,6 +6122,8 @@ zlib_decompress_section (struct objfile *objfile, asection *sectp, + error (_("Dwarf Error: concluding DWARF uncompression in '%s': %d"), + bfd_get_filename (abfd), rc); + ++ if (old) ++ discard_cleanups (old); + xfree (compressed_buffer); + *outbuf = uncompressed_buffer; + *outsize = uncompressed_size; +@@ -5463,17 +6131,20 @@ zlib_decompress_section (struct objfile *objfile, asection *sectp, + } + + +-/* Read the contents of the section at OFFSET and of size SIZE from the +- object file specified by OBJFILE into the objfile_obstack and return it. +- If the section is compressed, uncompress it before returning. */ ++/* Read the contents of the section at OFFSET and of size SIZE from ++ the object file specified by OBJFILE into OBSTACK and return it. ++ If OBSTACK is NULL, xmalloc is used instead. If the section is ++ compressed, uncompress it before returning. */ + +-gdb_byte * +-dwarf2_read_section (struct objfile *objfile, asection *sectp) ++static gdb_byte * ++dwarf2_read_section_1 (struct objfile *objfile, struct obstack *obstack, ++ asection *sectp) + { + bfd *abfd = objfile->obfd; + gdb_byte *buf, *retbuf; + bfd_size_type size = bfd_get_section_size (sectp); + unsigned char header[4]; ++ struct cleanup *old = NULL; + + if (size == 0) + return NULL; +@@ -5486,30 +6157,49 @@ dwarf2_read_section (struct objfile *objfile, asection *sectp) + /* Upon decompression, update the buffer and its size. */ + if (strncmp (header, "ZLIB", sizeof (header)) == 0) + { +- zlib_decompress_section (objfile, sectp, &buf, &size); ++ zlib_decompress_section (objfile, obstack, sectp, &buf, &size); + dwarf2_resize_section (sectp, size); + return buf; + } + } + + /* If we get here, we are a normal, not-compressed section. */ +- buf = obstack_alloc (&objfile->objfile_obstack, size); ++ if (obstack) ++ buf = obstack_alloc (obstack, size); ++ else ++ { ++ buf = xmalloc (size); ++ old = make_cleanup (xfree, buf); ++ } + /* When debugging .o files, we may need to apply relocations; see + http://sourceware.org/ml/gdb-patches/2002-04/msg00136.html . + We never compress sections in .o files, so we only need to + try this when the section is not compressed. */ + retbuf = symfile_relocate_debug_section (abfd, sectp, buf); + if (retbuf != NULL) +- return retbuf; ++ { ++ if (old) ++ discard_cleanups (old); ++ return retbuf; ++ } + + if (bfd_seek (abfd, sectp->filepos, SEEK_SET) != 0 + || bfd_bread (buf, size, abfd) != size) + error (_("Dwarf Error: Can't read DWARF data from '%s'"), + bfd_get_filename (abfd)); + ++ if (old) ++ discard_cleanups (old); ++ + return buf; + } + ++gdb_byte * ++dwarf2_read_section (struct objfile *objfile, asection *sectp) ++{ ++ return dwarf2_read_section_1 (objfile, &objfile->objfile_obstack, sectp); ++} ++ + /* In DWARF version 2, the description of the debugging information is + stored in a separate .debug_abbrev section. Before we read any + dies from a section we read in all abbreviations and install them +@@ -5914,15 +6604,6 @@ read_partial_die (struct partial_die_info *part_die, + struct attribute attr; + int has_low_pc_attr = 0; + int has_high_pc_attr = 0; +- CORE_ADDR base_address = 0; +- enum +- { +- base_address_none, +- base_address_low_pc, +- /* Overrides BASE_ADDRESS_LOW_PC. */ +- base_address_entry_pc +- } +- base_address_type = base_address_none; + + memset (part_die, 0, sizeof (struct partial_die_info)); + +@@ -5945,47 +6626,35 @@ read_partial_die (struct partial_die_info *part_die, + switch (attr.name) + { + case DW_AT_name: +- +- /* Prefer DW_AT_MIPS_linkage_name over DW_AT_name. */ +- if (part_die->name == NULL) +- part_die->name = DW_STRING (&attr); +- break; +- case DW_AT_comp_dir: +- if (part_die->dirname == NULL) +- part_die->dirname = DW_STRING (&attr); ++ switch (part_die->tag) ++ { ++ case DW_TAG_compile_unit: ++ /* Compilation units have a DW_AT_name that is a filename, not ++ a source language identifier. */ ++ case DW_TAG_enumeration_type: ++ case DW_TAG_enumerator: ++ /* These tags always have simple identifiers already; no need ++ to canonicalize them. */ ++ part_die->name = DW_STRING (&attr); ++ break; ++ default: ++ part_die->name ++ = dwarf2_canonicalize_name (DW_STRING (&attr), cu, ++ &cu->comp_unit_obstack); ++ break; ++ } + break; + case DW_AT_MIPS_linkage_name: +- part_die->name = DW_STRING (&attr); ++ part_die->linkage_name = DW_STRING (&attr); + break; + case DW_AT_low_pc: + has_low_pc_attr = 1; + part_die->lowpc = DW_ADDR (&attr); +- if (part_die->tag == DW_TAG_compile_unit +- && base_address_type < base_address_low_pc) +- { +- base_address = DW_ADDR (&attr); +- base_address_type = base_address_low_pc; +- } + break; + case DW_AT_high_pc: + has_high_pc_attr = 1; + part_die->highpc = DW_ADDR (&attr); + break; +- case DW_AT_entry_pc: +- if (part_die->tag == DW_TAG_compile_unit +- && base_address_type < base_address_entry_pc) +- { +- base_address = DW_ADDR (&attr); +- base_address_type = base_address_entry_pc; +- } +- break; +- case DW_AT_ranges: +- if (part_die->tag == DW_TAG_compile_unit) +- { +- cu->ranges_offset = DW_UNSND (&attr); +- cu->has_ranges_offset = 1; +- } +- break; + case DW_AT_location: + /* Support the .debug_loc offsets */ + if (attr_form_is_block (&attr)) +@@ -6002,9 +6671,6 @@ read_partial_die (struct partial_die_info *part_die, + "partial symbol information"); + } + break; +- case DW_AT_language: +- part_die->language = DW_UNSND (&attr); +- break; + case DW_AT_external: + part_die->is_external = DW_UNSND (&attr); + break; +@@ -6029,10 +6695,6 @@ read_partial_die (struct partial_die_info *part_die, + part_die->sibling = dwarf2_per_objfile->info_buffer + + dwarf2_get_ref_die_offset (&attr); + break; +- case DW_AT_stmt_list: +- part_die->has_stmt_list = 1; +- part_die->line_offset = DW_UNSND (&attr); +- break; + case DW_AT_byte_size: + part_die->has_byte_size = 1; + break; +@@ -6074,13 +6736,6 @@ read_partial_die (struct partial_die_info *part_die, + || dwarf2_per_objfile->has_section_at_zero)) + part_die->has_pc_info = 1; + +- if (base_address_type != base_address_none && !cu->base_known) +- { +- gdb_assert (part_die->tag == DW_TAG_compile_unit); +- cu->base_known = 1; +- cu->base_address = base_address; +- } +- + return info_ptr; + } + +@@ -6173,7 +6828,9 @@ fixup_partial_die (struct partial_die_info *part_die, + /* If we found a reference attribute and the DIE has no name, try + to find a name in the referred to DIE. */ + +- if (part_die->name == NULL && part_die->has_specification) ++ if (part_die->has_specification ++ && (part_die->name == NULL || part_die->linkage_name == NULL ++ || !part_die->is_external)) + { + struct partial_die_info *spec_die; + +@@ -6189,6 +6846,9 @@ fixup_partial_die (struct partial_die_info *part_die, + if (spec_die->is_external) + part_die->is_external = spec_die->is_external; + } ++ ++ if (spec_die->linkage_name) ++ part_die->linkage_name = spec_die->linkage_name; + } + + /* Set default names for some unnamed DIEs. */ +@@ -7512,10 +8172,12 @@ var_decode_location (struct attribute *attr, struct symbol *sym, + (i.e. when the value of a register or memory location is + referenced, or a thread-local block, etc.). Then again, it might + not be worthwhile. I'm assuming that it isn't unless performance +- or memory numbers show me otherwise. */ ++ or memory numbers show me otherwise. ++ ++ SYMBOL_CLASS may get overriden by dwarf2_symbol_mark_computed. */ + +- dwarf2_symbol_mark_computed (attr, sym, cu); + SYMBOL_CLASS (sym) = LOC_COMPUTED; ++ dwarf2_symbol_mark_computed (attr, sym, cu); + } + + /* Given a pointer to a DWARF information entry, figure out if we need +@@ -7538,20 +8200,43 @@ new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu) + baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); + + if (die->tag != DW_TAG_namespace) +- name = dwarf2_linkage_name (die, cu); ++ name = dwarf2_name (die, cu); + else + name = TYPE_NAME (type); + + if (name) + { ++ const char *linkagename; ++ + sym = (struct symbol *) obstack_alloc (&objfile->objfile_obstack, + sizeof (struct symbol)); + OBJSTAT (objfile, n_syms++); + memset (sym, 0, sizeof (struct symbol)); ++ /* Some methods are called without checking SYMBOL_OPS validity. */ ++ SYMBOL_OPS (sym) = &dwarf2_missing_funcs; + +- /* Cache this symbol's name and the name's demangled form (if any). */ + SYMBOL_LANGUAGE (sym) = cu->language; +- SYMBOL_SET_NAMES (sym, name, strlen (name), objfile); ++ ++ /* Cache this symbol's name and the name's demangled form (if any). */ ++ ++ linkagename = dwarf2_linkage_name (die, cu); ++ if (linkagename) ++ /* We use the linkage name if available, for the same reason ++ we used it for TYPE_FN_FIELD_PHYSNAME earlier in this file. ++ This usage can be removed someday. */ ++ SYMBOL_SET_NAMES (sym, linkagename, strlen (linkagename), objfile); ++ else if (die->tag == DW_TAG_namespace) ++ SYMBOL_SET_LINKAGE_NAME (sym, name); ++ else ++ { ++ linkagename = dwarf2_full_name (die, cu); ++ ++ /* Set just the "linkage" name to the fully qualified name. ++ While this is not really a linkage name, it should match ++ the demangled version of the corresponding minimal symbol ++ if there is one. */ ++ SYMBOL_SET_LINKAGE_NAME (sym, (char *) linkagename); ++ } + + /* Default assumptions. + Use the passed type or decode it from the die. */ +@@ -7637,7 +8322,15 @@ new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu) + if (attr) + { + var_decode_location (attr, sym, cu); +- attr2 = dwarf2_attr (die, DW_AT_external, cu); ++ ++ /* Fortran explicitely imports any global symbols to the local ++ scope by DW_TAG_common_block. DW_AT_external means for ++ Fortran the variable is importable versus it is automatically ++ imported. */ ++ if (cu->language == language_fortran) ++ attr2 = NULL; ++ else ++ attr2 = dwarf2_attr (die, DW_AT_external, cu); + if (attr2 && (DW_UNSND (attr2) != 0)) + add_symbol_to_list (sym, &global_symbols); + else +@@ -7780,6 +8473,11 @@ new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu) + SYMBOL_CLASS (sym) = LOC_TYPEDEF; + add_symbol_to_list (sym, &global_symbols); + break; ++ case DW_TAG_common_block: ++ SYMBOL_CLASS (sym) = LOC_STATIC; ++ SYMBOL_DOMAIN (sym) = COMMON_BLOCK_DOMAIN; ++ add_symbol_to_list (sym, cu->list_in_scope); ++ break; + default: + /* Not a tag we recognize. Hopefully we aren't processing + trash data, but since we must specifically ignore things +@@ -8048,6 +8746,9 @@ read_type_die (struct die_info *die, struct dwarf2_cu *cu) + break; + } + ++ if (this_type) ++ finalize_type (this_type); ++ + return this_type; + } + +@@ -8128,6 +8829,19 @@ determine_prefix (struct die_info *die, struct dwarf2_cu *cu) + members; no typedefs, no member functions, et cetera. + So it does not need a prefix. */ + return ""; ++ ++ case DW_TAG_subprogram: ++ /* A class's symbol, or a variable's symbol, will live ++ directly in a function's block, so no prefix is ++ appropriate. However, what about methods of a ++ function-local class? They end up in the global symbol ++ table because they are separate functions... their mangling ++ normally would make them inaccessible. They'll show up ++ wrong in breakpoints too. This is a symptom of the ++ inconsistent way we handle symbol tables. Namespaces and ++ classes should have dictionaries just like blocks do. */ ++ return ""; ++ + default: + return determine_prefix (parent, cu); + } +@@ -8192,23 +8906,62 @@ dwarf2_linkage_name (struct die_info *die, struct dwarf2_cu *cu) + attr = dwarf2_attr (die, DW_AT_MIPS_linkage_name, cu); + if (attr && DW_STRING (attr)) + return DW_STRING (attr); +- attr = dwarf2_attr (die, DW_AT_name, cu); +- if (attr && DW_STRING (attr)) +- return DW_STRING (attr); + return NULL; + } + + /* Get name of a die, return NULL if not found. */ + + static char * ++dwarf2_canonicalize_name (char *name, struct dwarf2_cu *cu, ++ struct obstack *obstack) ++{ ++ if (cu->language == language_cplus) ++ { ++ char *canon_name = cp_canonicalize_string (name); ++ ++ if (canon_name != NULL) ++ { ++ if (strcmp (canon_name, name) != 0) ++ name = obsavestring (canon_name, strlen (canon_name), ++ obstack); ++ xfree (canon_name); ++ } ++ } ++ ++ return name; ++} ++ ++/* Get name of a die, return NULL if not found. */ ++ ++static char * + dwarf2_name (struct die_info *die, struct dwarf2_cu *cu) + { + struct attribute *attr; + + attr = dwarf2_attr (die, DW_AT_name, cu); +- if (attr && DW_STRING (attr)) +- return DW_STRING (attr); +- return NULL; ++ if (!attr || !DW_STRING (attr)) ++ return NULL; ++ ++ switch (die->tag) ++ { ++ case DW_TAG_compile_unit: ++ /* Compilation units have a DW_AT_name that is a filename, not ++ a source language identifier. */ ++ case DW_TAG_enumeration_type: ++ case DW_TAG_enumerator: ++ /* These tags always have simple identifiers already; no need ++ to canonicalize them. */ ++ return DW_STRING (attr); ++ default: ++ if (attr->form != GDB_FORM_cached_string) ++ { ++ DW_STRING (attr) ++ = dwarf2_canonicalize_name (DW_STRING (attr), cu, ++ &cu->objfile->objfile_obstack); ++ attr->form = GDB_FORM_cached_string; ++ } ++ return DW_STRING (attr); ++ } + } + + /* Return the die that this die in an extension of, or NULL if there +@@ -8703,6 +9456,8 @@ dwarf_form_name (unsigned form) + return "DW_FORM_ref_udata"; + case DW_FORM_indirect: + return "DW_FORM_indirect"; ++ case GDB_FORM_cached_string: ++ return "GDB_FORM_cached_string"; + default: + return "DW_FORM_"; + } +@@ -9248,6 +10003,7 @@ dump_die_shallow (struct ui_file *f, int indent, struct die_info *die) + break; + case DW_FORM_string: + case DW_FORM_strp: ++ case GDB_FORM_cached_string: + fprintf_unfiltered (f, "string: \"%s\"", + DW_STRING (&die->attrs[i]) + ? DW_STRING (&die->attrs[i]) : ""); +@@ -9353,26 +10109,35 @@ dwarf2_get_ref_die_offset (struct attribute *attr) + return result; + } + +-/* Return the constant value held by the given attribute. Return -1 +- if the value held by the attribute is not constant. */ ++/* (*val_return) is filled only if returning dwarf2_attr_const. */ + +-static int +-dwarf2_get_attr_constant_value (struct attribute *attr, int default_value) ++static enum dwarf2_get_attr_constant_value ++dwarf2_get_attr_constant_value (struct attribute *attr, int *val_return) + { ++ if (attr == NULL) ++ return dwarf2_attr_unknown; + if (attr->form == DW_FORM_sdata) +- return DW_SND (attr); +- else if (attr->form == DW_FORM_udata +- || attr->form == DW_FORM_data1 +- || attr->form == DW_FORM_data2 +- || attr->form == DW_FORM_data4 +- || attr->form == DW_FORM_data8) +- return DW_UNSND (attr); +- else + { +- complaint (&symfile_complaints, _("Attribute value is not a constant (%s)"), +- dwarf_form_name (attr->form)); +- return default_value; ++ *val_return = DW_SND (attr); ++ return dwarf2_attr_const; + } ++ if (attr->form == DW_FORM_udata ++ || attr->form == DW_FORM_data1 ++ || attr->form == DW_FORM_data2 ++ || attr->form == DW_FORM_data4 ++ || attr->form == DW_FORM_data8) ++ { ++ *val_return = DW_UNSND (attr); ++ return dwarf2_attr_const; ++ } ++ if (attr->form == DW_FORM_block ++ || attr->form == DW_FORM_block1 ++ || attr->form == DW_FORM_block2 ++ || attr->form == DW_FORM_block4) ++ return dwarf2_attr_block; ++ complaint (&symfile_complaints, _("Attribute value is not a constant (%s)"), ++ dwarf_form_name (attr->form)); ++ return dwarf2_attr_unknown; + } + + /* THIS_CU has a reference to PER_CU. If necessary, load the new compilation +@@ -9963,6 +10728,17 @@ dwarf_decode_macros (struct line_header *lh, unsigned int offset, + { + gdb_byte *mac_ptr, *mac_end; + struct macro_source_file *current_file = 0; ++ enum dwarf_macinfo_record_type macinfo_type; ++ ++ /* Flag is in use by the second pass and determines if GDB is still before ++ first DW_MACINFO_start_file. If true GDB is still reading the definitions ++ from command line. First DW_MACINFO_start_file will need to be ignored as ++ it was already executed to create CURRENT_FILE for the main source holding ++ also the command line definitions. On first met DW_MACINFO_start_file ++ this flag is reset to normally execute all the remaining ++ DW_MACINFO_start_file macinfos. */ ++ ++ int at_commandline; + + if (dwarf2_per_objfile->macinfo_buffer == NULL) + { +@@ -9970,19 +10746,24 @@ dwarf_decode_macros (struct line_header *lh, unsigned int offset, + return; + } + ++ /* Start the first pass to find ahead the main source file name. GDB has to ++ create CURRENT_FILE where to place the macros given to the compiler ++ from the command line. Such command line macros are present before first ++ DW_MACINFO_start_file but still those macros are associated to the ++ compilation unit. The compilation unit GDB identifies by its main source ++ file name. */ ++ + mac_ptr = dwarf2_per_objfile->macinfo_buffer + offset; + mac_end = dwarf2_per_objfile->macinfo_buffer + + dwarf2_per_objfile->macinfo_size; + +- for (;;) ++ do + { +- enum dwarf_macinfo_record_type macinfo_type; +- + /* Do we at least have room for a macinfo type byte? */ + if (mac_ptr >= mac_end) + { + dwarf2_macros_too_long_complaint (); +- return; ++ break; + } + + macinfo_type = read_1_byte (abfd, mac_ptr); +@@ -9993,7 +10774,81 @@ dwarf_decode_macros (struct line_header *lh, unsigned int offset, + /* A zero macinfo type indicates the end of the macro + information. */ + case 0: +- return; ++ break; ++ ++ case DW_MACINFO_define: ++ case DW_MACINFO_undef: ++ /* Only skip the data by MAC_PTR. */ ++ { ++ unsigned int bytes_read; ++ ++ read_unsigned_leb128 (abfd, mac_ptr, &bytes_read); ++ mac_ptr += bytes_read; ++ read_string (abfd, mac_ptr, &bytes_read); ++ mac_ptr += bytes_read; ++ } ++ break; ++ ++ case DW_MACINFO_start_file: ++ { ++ unsigned int bytes_read; ++ int line, file; ++ ++ line = read_unsigned_leb128 (abfd, mac_ptr, &bytes_read); ++ mac_ptr += bytes_read; ++ file = read_unsigned_leb128 (abfd, mac_ptr, &bytes_read); ++ mac_ptr += bytes_read; ++ ++ current_file = macro_start_file (file, line, current_file, comp_dir, ++ lh, cu->objfile); ++ } ++ break; ++ ++ case DW_MACINFO_end_file: ++ /* No data to skip by MAC_PTR. */ ++ break; ++ ++ case DW_MACINFO_vendor_ext: ++ /* Only skip the data by MAC_PTR. */ ++ { ++ unsigned int bytes_read; ++ ++ read_unsigned_leb128 (abfd, mac_ptr, &bytes_read); ++ mac_ptr += bytes_read; ++ read_string (abfd, mac_ptr, &bytes_read); ++ mac_ptr += bytes_read; ++ } ++ break; ++ ++ default: ++ break; ++ } ++ } while (macinfo_type != 0 && current_file == NULL); ++ ++ /* Here is the second pass to read in the macros starting from the ones ++ defined at the command line. */ ++ ++ mac_ptr = dwarf2_per_objfile->macinfo_buffer + offset; ++ at_commandline = 1; ++ ++ do ++ { ++ /* Do we at least have room for a macinfo type byte? */ ++ if (mac_ptr >= mac_end) ++ { ++ /* Complaint is in the first pass above. */ ++ break; ++ } ++ ++ macinfo_type = read_1_byte (abfd, mac_ptr); ++ mac_ptr++; ++ ++ switch (macinfo_type) ++ { ++ /* A zero macinfo type indicates the end of the macro ++ information. */ ++ case 0: ++ break; + + case DW_MACINFO_define: + case DW_MACINFO_undef: +@@ -10008,19 +10863,31 @@ dwarf_decode_macros (struct line_header *lh, unsigned int offset, + mac_ptr += bytes_read; + + if (! current_file) ++ { ++ /* DWARF violation as no main source is present. */ ++ complaint (&symfile_complaints, ++ _("debug info with no main source gives macro %s " ++ "on line %d: %s"), ++ macinfo_type == ++ DW_MACINFO_define ? _("definition") : macinfo_type == ++ DW_MACINFO_undef ? _("undefinition") : ++ "something-or-other", line, body); ++ break; ++ } ++ if (at_commandline != (line == 0)) + complaint (&symfile_complaints, +- _("debug info gives macro %s outside of any file: %s"), ++ _("debug info gives %s macro %s with %s line %d: %s"), ++ at_commandline ? _("command-line") : _("in-file"), + macinfo_type == +- DW_MACINFO_define ? "definition" : macinfo_type == +- DW_MACINFO_undef ? "undefinition" : +- "something-or-other", body); +- else +- { +- if (macinfo_type == DW_MACINFO_define) +- parse_macro_definition (current_file, line, body); +- else if (macinfo_type == DW_MACINFO_undef) +- macro_undef (current_file, line, body); +- } ++ DW_MACINFO_define ? _("definition") : macinfo_type == ++ DW_MACINFO_undef ? _("undefinition") : ++ "something-or-other", ++ line == 0 ? _("zero") : _("non-zero"), line, body); ++ ++ if (macinfo_type == DW_MACINFO_define) ++ parse_macro_definition (current_file, line, body); ++ else if (macinfo_type == DW_MACINFO_undef) ++ macro_undef (current_file, line, body); + } + break; + +@@ -10034,9 +10901,22 @@ dwarf_decode_macros (struct line_header *lh, unsigned int offset, + file = read_unsigned_leb128 (abfd, mac_ptr, &bytes_read); + mac_ptr += bytes_read; + +- current_file = macro_start_file (file, line, +- current_file, comp_dir, +- lh, cu->objfile); ++ if (at_commandline != (line == 0)) ++ complaint (&symfile_complaints, ++ _("debug info gives source %d included " ++ "from %s at %s line %d"), ++ file, at_commandline ? _("command-line") : _("file"), ++ line == 0 ? _("zero") : _("non-zero"), line); ++ ++ if (at_commandline) ++ { ++ /* This DW_MACINFO_start_file was executed in the pass one. */ ++ at_commandline = 0; ++ } ++ else ++ current_file = macro_start_file (file, line, ++ current_file, comp_dir, ++ lh, cu->objfile); + } + break; + +@@ -10090,7 +10970,7 @@ dwarf_decode_macros (struct line_header *lh, unsigned int offset, + } + break; + } +- } ++ } while (macinfo_type != 0); + } + + /* Check if the attribute's form is a DW_FORM_block* +@@ -10150,6 +11030,34 @@ attr_form_is_constant (struct attribute *attr) + } + } + ++/* Convert DW_BLOCK into struct dwarf2_locexpr_baton. ATTR must be a DW_BLOCK ++ attribute type. */ ++ ++static struct dwarf2_locexpr_baton * ++dwarf2_attr_to_locexpr_baton (struct attribute *attr, struct dwarf2_cu *cu) ++{ ++ struct dwarf2_locexpr_baton *baton; ++ ++ gdb_assert (attr_form_is_block (attr)); ++ ++ baton = obstack_alloc (&cu->objfile->objfile_obstack, sizeof (*baton)); ++ baton->per_cu = cu->per_cu; ++ gdb_assert (baton->per_cu); ++ ++ /* Note that we're just copying the block's data pointer ++ here, not the actual data. We're still pointing into the ++ info_buffer for SYM's objfile; right now we never release ++ that buffer, but when we do clean up properly this may ++ need to change. */ ++ baton->size = DW_BLOCK (attr)->size; ++ baton->data = DW_BLOCK (attr)->data; ++ gdb_assert (baton->size == 0 || baton->data != NULL); ++ ++ return baton; ++} ++ ++/* SYM may get its SYMBOL_CLASS overriden on invalid ATTR content. */ ++ + static void + dwarf2_symbol_mark_computed (struct attribute *attr, struct symbol *sym, + struct dwarf2_cu *cu) +@@ -10179,35 +11087,24 @@ dwarf2_symbol_mark_computed (struct attribute *attr, struct symbol *sym, + SYMBOL_OPS (sym) = &dwarf2_loclist_funcs; + SYMBOL_LOCATION_BATON (sym) = baton; + } ++ else if (attr_form_is_block (attr)) ++ { ++ SYMBOL_OPS (sym) = &dwarf2_locexpr_funcs; ++ SYMBOL_LOCATION_BATON (sym) = dwarf2_attr_to_locexpr_baton (attr, cu); ++ } + else + { +- struct dwarf2_locexpr_baton *baton; ++ dwarf2_invalid_attrib_class_complaint ("location description", ++ SYMBOL_NATURAL_NAME (sym)); + +- baton = obstack_alloc (&cu->objfile->objfile_obstack, +- sizeof (struct dwarf2_locexpr_baton)); +- baton->per_cu = cu->per_cu; +- gdb_assert (baton->per_cu); ++ /* Some methods are called without checking SYMBOL_OPS validity. */ ++ SYMBOL_OPS (sym) = &dwarf2_missing_funcs; ++ SYMBOL_LOCATION_BATON (sym) = NULL; + +- if (attr_form_is_block (attr)) +- { +- /* Note that we're just copying the block's data pointer +- here, not the actual data. We're still pointing into the +- info_buffer for SYM's objfile; right now we never release +- that buffer, but when we do clean up properly this may +- need to change. */ +- baton->size = DW_BLOCK (attr)->size; +- baton->data = DW_BLOCK (attr)->data; +- } +- else +- { +- dwarf2_invalid_attrib_class_complaint ("location description", +- SYMBOL_NATURAL_NAME (sym)); +- baton->size = 0; +- baton->data = NULL; +- } +- +- SYMBOL_OPS (sym) = &dwarf2_locexpr_funcs; +- SYMBOL_LOCATION_BATON (sym) = baton; ++ /* For functions a missing DW_AT_frame_base does not optimize out the ++ whole function definition, only its frame base resolving. */ ++ if (attr->name == DW_AT_location) ++ SYMBOL_CLASS (sym) = LOC_OPTIMIZED_OUT; + } + } + +@@ -10482,6 +11379,31 @@ offset_and_type_eq (const void *item_lhs, const void *item_rhs) + return ofs_lhs->offset == ofs_rhs->offset; + } + ++/* Fill in generic attributes applicable for type DIEs. */ ++ ++static void ++fetch_die_type_attrs (struct die_info *die, struct type *type, ++ struct dwarf2_cu *cu) ++{ ++ struct attribute *attr; ++ ++ attr = dwarf2_attr (die, DW_AT_data_location, cu); ++ if (attr_form_is_block (attr)) ++ TYPE_DATA_LOCATION_DWARF_BLOCK (type) = dwarf2_attr_to_locexpr_baton (attr, ++ cu); ++ gdb_assert (!TYPE_DATA_LOCATION_IS_ADDR (type)); ++ ++ attr = dwarf2_attr (die, DW_AT_allocated, cu); ++ if (attr_form_is_block (attr)) ++ TYPE_ALLOCATED (type) = dwarf2_attr_to_locexpr_baton (attr, cu); ++ gdb_assert (!TYPE_NOT_ALLOCATED (type)); ++ ++ attr = dwarf2_attr (die, DW_AT_associated, cu); ++ if (attr_form_is_block (attr)) ++ TYPE_ASSOCIATED (type) = dwarf2_attr_to_locexpr_baton (attr, cu); ++ gdb_assert (!TYPE_NOT_ASSOCIATED (type)); ++} ++ + /* Set the type associated with DIE to TYPE. Save it in CU's hash + table if necessary. For convenience, return TYPE. */ + +@@ -10490,6 +11412,8 @@ set_die_type (struct die_info *die, struct type *type, struct dwarf2_cu *cu) + { + struct dwarf2_offset_and_type **slot, ofs; + ++ fetch_die_type_attrs (die, type, cu); ++ + if (cu->type_hash == NULL) + { + gdb_assert (cu->per_cu != NULL); +diff --git a/gdb/elfread.c b/gdb/elfread.c +index ff220a2..13158f4 100644 +--- a/gdb/elfread.c ++++ b/gdb/elfread.c +@@ -727,10 +727,18 @@ elf_symfile_read (struct objfile *objfile, int mainline) + str_sect->filepos, + bfd_section_size (abfd, str_sect)); + } ++ ++ if (dwarf2_has_info (objfile)) ++ dwarf2_create_quick_addrmap (objfile); ++} ++ ++static void ++read_psyms (struct objfile *objfile) ++{ + if (dwarf2_has_info (objfile)) + { + /* DWARF 2 sections */ +- dwarf2_build_psymtabs (objfile, mainline); ++ dwarf2_build_psymtabs (objfile, 0); + } + + /* FIXME: kettenis/20030504: This still needs to be integrated with +@@ -880,6 +888,7 @@ static struct sym_fns elf_sym_fns = + elf_new_init, /* sym_new_init: init anything gbl to entire symtab */ + elf_symfile_init, /* sym_init: read initial info, setup for sym_read() */ + elf_symfile_read, /* sym_read: read a symbol file into symtab */ ++ read_psyms, /* sym_read_psymbols */ + elf_symfile_finish, /* sym_finish: finished with file, cleanup */ + default_symfile_offsets, /* sym_offsets: Translate ext. to int. relocation */ + elf_symfile_segments, /* sym_segments: Get segment information from +diff --git a/gdb/eval.c b/gdb/eval.c +index 1d35571..6a97e09 100644 +--- a/gdb/eval.c ++++ b/gdb/eval.c +@@ -39,10 +39,16 @@ + #include "exceptions.h" + #include "regcache.h" + #include "user-regs.h" ++#include "python/python.h" + #include "valprint.h" ++#include "dwarf2loc.h" ++#include "gdb_obstack.h" ++#include "objfiles.h" + + #include "gdb_assert.h" + ++#include ++ + /* This is defined in valops.c */ + extern int overload_resolution; + +@@ -651,6 +657,64 @@ ptrmath_type_p (struct type *type) + } + } + ++/* Compares the two method/function types T1 and T2 for "equality" ++ with respect to the the methods' parameters. If the types of the ++ two parameter lists are the same, returns 1; 0 otherwise. This ++ comparison ignores any artificial this pointer. */ ++int ++compare_parameters (struct type *t1, struct type *t2) ++{ ++ int i, has_this; ++ /* Hacky: we don't know a priori whether or not t1 is a static ++ method, so we skip any artificial "this" pointer and hope ++ for the best. t2, which comes as user input, never contains a ++ "this" pointer (a user would never enter it into expressions. */ ++ if (TYPE_NFIELDS (t1) > 0) ++ has_this = TYPE_FIELD_ARTIFICIAL (t1, 0) ? 1 : 0; ++ else ++ has_this = 0; ++ ++ /* Special case: a method taking void. t1 will contain either ++ no fields or just "this". t2 will contain TYPE_CODE_VOID. */ ++ if ((TYPE_NFIELDS (t1) - has_this) == 0 && TYPE_NFIELDS (t2) == 1 ++ && TYPE_CODE (TYPE_FIELD_TYPE (t2, 0)) == TYPE_CODE_VOID) ++ return 1; ++ ++ if ((TYPE_NFIELDS (t1) - has_this) == TYPE_NFIELDS (t2)) ++ { ++ for (i = has_this; i < TYPE_NFIELDS (t1); ++i) ++ { ++ if (rank_one_type (TYPE_FIELD_TYPE (t1, i), ++ TYPE_FIELD_TYPE (t2, i - has_this)) ++ != 0) ++ return 0; ++ } ++ ++ return 1; ++ } ++ ++ return 0; ++} ++ ++/* Constructs a fake method with the given parameter types. */ ++ ++static struct type * ++make_params (int num_types, struct type **param_types) ++{ ++ struct type *type = alloc_type (NULL, NULL); ++ TYPE_LENGTH (type) = 1; ++ TYPE_CODE (type) = TYPE_CODE_METHOD; ++ TYPE_NFIELDS (type) = num_types; ++ TYPE_FIELDS (type) = (struct field *) ++ TYPE_ALLOC (type, sizeof (struct field) * num_types); ++ memset (TYPE_FIELDS (type), 0, sizeof (struct field) * num_types); ++ ++ while (num_types-- > 0) ++ TYPE_FIELD_TYPE (type, num_types) = param_types[num_types]; ++ ++ return type; ++} ++ + struct value * + evaluate_subexp_standard (struct type *expect_type, + struct expression *exp, int *pos, +@@ -671,6 +735,7 @@ evaluate_subexp_standard (struct type *expect_type, + long mem_offset; + struct type **arg_types; + int save_pos1; ++ struct cleanup *old_chain; + + pc = (*pos)++; + op = exp->elts[pc].opcode; +@@ -684,7 +749,7 @@ evaluate_subexp_standard (struct type *expect_type, + goto nosideret; + arg1 = value_aggregate_elt (exp->elts[pc + 1].type, + &exp->elts[pc + 3].string, +- 0, noside); ++ expect_type, 0, noside); + if (arg1 == NULL) + error (_("There is no field named %s"), &exp->elts[pc + 3].string); + return arg1; +@@ -1208,9 +1273,9 @@ evaluate_subexp_standard (struct type *expect_type, + if (TYPE_CODE (value_type (method)) != TYPE_CODE_FUNC) + error (_("method address has symbol information with non-function type; skipping")); + if (struct_return) +- VALUE_ADDRESS (method) = value_as_address (msg_send_stret); ++ set_value_address (method, value_as_address (msg_send_stret)); + else +- VALUE_ADDRESS (method) = value_as_address (msg_send); ++ set_value_address (method, value_as_address (msg_send)); + called_method = method; + } + else +@@ -1284,7 +1349,6 @@ evaluate_subexp_standard (struct type *expect_type, + argvec = (struct value **) alloca (sizeof (struct value *) * (nargs + 3)); + if (op == STRUCTOP_MEMBER || op == STRUCTOP_MPTR) + { +- nargs++; + /* First, evaluate the structure into arg2 */ + pc2 = (*pos)++; + +@@ -1308,21 +1372,40 @@ evaluate_subexp_standard (struct type *expect_type, + + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + +- if (TYPE_CODE (check_typedef (value_type (arg1))) +- != TYPE_CODE_METHODPTR) +- error (_("Non-pointer-to-member value used in pointer-to-member " +- "construct")); +- +- if (noside == EVAL_AVOID_SIDE_EFFECTS) ++ type = check_typedef (value_type (arg1)); ++ switch (TYPE_CODE (type)) + { +- struct type *method_type = check_typedef (value_type (arg1)); +- arg1 = value_zero (method_type, not_lval); ++ case TYPE_CODE_METHODPTR: ++ if (noside == EVAL_AVOID_SIDE_EFFECTS) ++ arg1 = value_zero (TYPE_TARGET_TYPE (type), not_lval); ++ else ++ arg1 = cplus_method_ptr_to_value (&arg2, arg1); ++ ++ /* Now, say which argument to start evaluating from */ ++ nargs++; ++ tem = 2; ++ argvec[1] = arg2; ++ break; ++ ++ case TYPE_CODE_MEMBERPTR: ++ /* Now, convert these values to an address. */ ++ arg2 = value_cast (lookup_pointer_type (TYPE_DOMAIN_TYPE (type)), ++ arg2); ++ ++ mem_offset = value_as_long (arg1); ++ ++ arg1 = value_from_pointer (lookup_pointer_type (TYPE_TARGET_TYPE (type)), ++ value_as_long (arg2) + mem_offset); ++ arg1 = value_ind (arg1); ++ tem = 1; ++ break; ++ ++ default: ++ error (_("Non-pointer-to-member value used in pointer-to-member " ++ "construct")); + } +- else +- arg1 = cplus_method_ptr_to_value (&arg2, arg1); + +- /* Now, say which argument to start evaluating from */ +- tem = 2; ++ argvec[0] = arg1; + } + else if (op == STRUCTOP_STRUCT || op == STRUCTOP_PTR) + { +@@ -1434,7 +1517,7 @@ evaluate_subexp_standard (struct type *expect_type, + of the ``this'' pointer if necessary, so modify argvec[1] to + reflect any ``this'' changes. */ + arg2 = value_from_longest (lookup_pointer_type(value_type (temp)), +- VALUE_ADDRESS (temp) + value_offset (temp) ++ value_address (temp) + + value_embedded_offset (temp)); + argvec[1] = arg2; /* the ``this'' pointer */ + } +@@ -1448,8 +1531,7 @@ evaluate_subexp_standard (struct type *expect_type, + } + else if (op == STRUCTOP_MEMBER || op == STRUCTOP_MPTR) + { +- argvec[1] = arg2; +- argvec[0] = arg1; ++ /* Pointer to member. argvec is already set up. */ + } + else if (op == OP_VAR_VALUE) + { +@@ -1512,6 +1594,9 @@ evaluate_subexp_standard (struct type *expect_type, + else + error (_("Expression of type other than \"Function returning ...\" used as function")); + } ++ if (TYPE_CODE (value_type (argvec[0])) == TYPE_CODE_INTERNAL_FUNCTION) ++ return call_internal_function (argvec[0], nargs, argvec + 1); ++ + return call_function_by_hand (argvec[0], nargs, argvec + 1); + /* pai: FIXME save value from call_function_by_hand, then adjust pc by adjust_fn_pc if +ve */ + +@@ -1529,7 +1614,10 @@ evaluate_subexp_standard (struct type *expect_type, + + /* First determine the type code we are dealing with. */ + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); ++ old_chain = make_cleanup (null_cleanup, 0); ++ object_address_set (VALUE_ADDRESS (arg1)); + type = check_typedef (value_type (arg1)); ++ do_cleanups (old_chain); + code = TYPE_CODE (type); + + if (code == TYPE_CODE_PTR) +@@ -1696,6 +1784,37 @@ evaluate_subexp_standard (struct type *expect_type, + error (_("non-pointer-to-member value used in pointer-to-member construct")); + } + ++ case TYPE_INSTANCE: ++ nargs = longest_to_int (exp->elts[pc + 1].longconst); ++ arg_types = (struct type **) alloca (nargs * sizeof (struct type *)); ++ for (ix = 0; ix < nargs; ++ix) ++ arg_types[ix] = exp->elts[pc + 1 + ix + 1].type; ++ ++ expect_type = make_params (nargs, arg_types); ++ *(pos) += 3 + nargs; ++ return evaluate_subexp_standard (expect_type, exp, pos, noside); ++ ++ case TYPE_INSTANCE_LOOKUP: ++ { ++ int i; ++ struct symbol *sym; ++ struct type **arg_types; ++ (*pos) += 3; ++ printf ("TYPE_INSTANCE_LOOKUP\n"); ++ arg_types = (struct type **) alloca (TYPE_NFIELDS (expect_type) ++ * sizeof (struct type *)); ++ for (i = 0; i < TYPE_NFIELDS (expect_type); ++i) ++ arg_types[i] = TYPE_FIELD_TYPE (expect_type, i); ++ (void) find_overload_match (arg_types, TYPE_NFIELDS (expect_type), ++ NULL /* no need for name */, ++ 0 /* not method */, ++ 0 /* strict match */, ++ NULL, exp->elts[pc + 1].symbol, NULL, ++ &sym, NULL); ++ i = 0; ++ } ++ break; ++ + case BINOP_CONCAT: + arg1 = evaluate_subexp_with_coercion (exp, pos, noside); + arg2 = evaluate_subexp_with_coercion (exp, pos, noside); +@@ -1963,13 +2082,19 @@ evaluate_subexp_standard (struct type *expect_type, + { + int subscript_array[MAX_FORTRAN_DIMS]; + int array_size_array[MAX_FORTRAN_DIMS]; ++ int byte_stride_array[MAX_FORTRAN_DIMS]; + int ndimensions = 1, i; + struct type *tmp_type; + int offset_item; /* The array offset where the item lives */ ++ CORE_ADDR offset_byte; /* byte_stride based offset */ ++ unsigned element_size; + + if (nargs > MAX_FORTRAN_DIMS) + error (_("Too many subscripts for F77 (%d Max)"), MAX_FORTRAN_DIMS); + ++ old_chain = make_cleanup (null_cleanup, 0); ++ object_address_set (VALUE_ADDRESS (arg1)); ++ + tmp_type = check_typedef (value_type (arg1)); + ndimensions = calc_f77_array_dims (type); + +@@ -1999,6 +2124,9 @@ evaluate_subexp_standard (struct type *expect_type, + upper = f77_get_upperbound (tmp_type); + lower = f77_get_lowerbound (tmp_type); + ++ byte_stride_array[nargs - i - 1] = ++ TYPE_ARRAY_BYTE_STRIDE_VALUE (tmp_type); ++ + array_size_array[nargs - i - 1] = upper - lower + 1; + + /* Zero-normalize subscripts so that offsetting will work. */ +@@ -2017,17 +2145,25 @@ evaluate_subexp_standard (struct type *expect_type, + tmp_type = check_typedef (TYPE_TARGET_TYPE (tmp_type)); + } + +- /* Now let us calculate the offset for this item */ ++ /* Kept for the f77_get_upperbound / f77_get_lowerbound calls above. */ ++ do_cleanups (old_chain); + +- offset_item = subscript_array[ndimensions - 1]; ++ /* Now let us calculate the offset for this item */ + +- for (i = ndimensions - 1; i > 0; --i) +- offset_item = +- array_size_array[i - 1] * offset_item + subscript_array[i - 1]; ++ offset_item = 0; ++ offset_byte = 0; + +- /* Construct a value node with the value of the offset */ ++ for (i = ndimensions - 1; i >= 0; --i) ++ { ++ offset_item *= array_size_array[i]; ++ if (byte_stride_array[i] == 0) ++ offset_item += subscript_array[i]; ++ else ++ offset_byte += subscript_array[i] * byte_stride_array[i]; ++ } + +- arg2 = value_from_longest (builtin_type_int32, offset_item); ++ element_size = TYPE_LENGTH (TYPE_TARGET_TYPE (tmp_type)); ++ offset_byte += offset_item * element_size; + + /* Let us now play a dirty trick: we will take arg1 + which is a value node pointing to the topmost level +@@ -2037,7 +2173,7 @@ evaluate_subexp_standard (struct type *expect_type, + returns the correct type value */ + + deprecated_set_value_type (arg1, tmp_type); +- return value_subscripted_rvalue (arg1, arg2, 0); ++ return value_subscripted_rvalue (arg1, offset_byte); + } + + case BINOP_LOGICAL_AND: +@@ -2475,7 +2611,17 @@ evaluate_subexp_standard (struct type *expect_type, + if (noside == EVAL_SKIP) + goto nosideret; + else if (noside == EVAL_AVOID_SIDE_EFFECTS) +- return allocate_value (exp->elts[pc + 1].type); ++ { ++ struct type *type = exp->elts[pc + 1].type; ++ /* If this is a typedef, then find its immediate target. We ++ use check_typedef to resolve stubs, but we ignore its ++ result because we do not want to dig past all ++ typedefs. */ ++ check_typedef (type); ++ if (TYPE_CODE (type) == TYPE_CODE_TYPEDEF) ++ type = TYPE_TARGET_TYPE (type); ++ return allocate_value (type); ++ } + else + error (_("Attempt to use a type name as an expression")); + +@@ -2568,7 +2714,7 @@ evaluate_subexp_for_address (struct expression *exp, int *pos, + (*pos) += 5 + BYTES_TO_EXP_ELEM (tem + 1); + x = value_aggregate_elt (exp->elts[pc + 1].type, + &exp->elts[pc + 3].string, +- 1, noside); ++ NULL, 1, noside); + if (x == NULL) + error (_("There is no field named %s"), &exp->elts[pc + 3].string); + return x; +@@ -2613,7 +2759,7 @@ evaluate_subexp_with_coercion (struct expression *exp, + { + enum exp_opcode op; + int pc; +- struct value *val; ++ struct value *val = NULL; + struct symbol *var; + struct type *type; + +@@ -2624,12 +2770,17 @@ evaluate_subexp_with_coercion (struct expression *exp, + { + case OP_VAR_VALUE: + var = exp->elts[pc + 2].symbol; ++ /* address_of_variable will call object_address_set for check_typedef. ++ Call it only if required as it can error-out on VAR in register. */ ++ if (TYPE_DYNAMIC (SYMBOL_TYPE (var))) ++ val = address_of_variable (var, exp->elts[pc + 1].block); + type = check_typedef (SYMBOL_TYPE (var)); + if (TYPE_CODE (type) == TYPE_CODE_ARRAY + && CAST_IS_CONVERSION) + { + (*pos) += 4; +- val = address_of_variable (var, exp->elts[pc + 1].block); ++ if (!val) ++ val = address_of_variable (var, exp->elts[pc + 1].block); + return value_cast (lookup_pointer_type (TYPE_TARGET_TYPE (type)), + val); + } +@@ -2681,9 +2832,13 @@ evaluate_subexp_for_sizeof (struct expression *exp, int *pos) + + case OP_VAR_VALUE: + (*pos) += 4; +- type = check_typedef (SYMBOL_TYPE (exp->elts[pc + 2].symbol)); +- return +- value_from_longest (size_type, (LONGEST) TYPE_LENGTH (type)); ++ /* We do not need to call read_var_value but the object evaluation may ++ need to have executed object_address_set which needs valid ++ SYMBOL_VALUE_ADDRESS of the symbol. Still VALUE returned by ++ read_var_value we left as lazy. */ ++ type = value_type (read_var_value (exp->elts[pc + 2].symbol, ++ deprecated_safe_get_selected_frame ())); ++ return value_from_longest (size_type, (LONGEST) TYPE_LENGTH (type)); + + default: + val = evaluate_subexp (NULL_TYPE, exp, pos, EVAL_AVOID_SIDE_EFFECTS); +diff --git a/gdb/expprint.c b/gdb/expprint.c +index 89bae03..f768940 100644 +--- a/gdb/expprint.c ++++ b/gdb/expprint.c +@@ -186,8 +186,8 @@ print_subexp_standard (struct expression *exp, int *pos, + If necessary, we can temporarily set it to zero, or pass it as an + additional parameter to LA_PRINT_STRING. -fnf */ + get_user_print_options (&opts); +- LA_PRINT_STRING (stream, &exp->elts[pc + 2].string, nargs, 1, 0, +- &opts); ++ LA_PRINT_STRING (stream, builtin_type (exp->gdbarch)->builtin_char, ++ &exp->elts[pc + 2].string, nargs, 0, &opts); + } + return; + +@@ -205,8 +205,8 @@ print_subexp_standard (struct expression *exp, int *pos, + (*pos) += 3 + BYTES_TO_EXP_ELEM (nargs + 1); + fputs_filtered ("@\"", stream); + get_user_print_options (&opts); +- LA_PRINT_STRING (stream, &exp->elts[pc + 2].string, nargs, 1, 0, +- &opts); ++ LA_PRINT_STRING (stream, builtin_type (exp->gdbarch)->builtin_char, ++ &exp->elts[pc + 2].string, nargs, 0, &opts); + fputs_filtered ("\"", stream); + } + return; +@@ -291,8 +291,8 @@ print_subexp_standard (struct expression *exp, int *pos, + { + struct value_print_options opts; + get_user_print_options (&opts); +- LA_PRINT_STRING (stream, tempstr, nargs - 1, 1, 0, +- &opts); ++ LA_PRINT_STRING (stream, builtin_type (exp->gdbarch)->builtin_char, ++ tempstr, nargs - 1, 0, &opts); + (*pos) = pc; + } + else +diff --git a/gdb/expression.h b/gdb/expression.h +index 12163e3..789cb89 100644 +--- a/gdb/expression.h ++++ b/gdb/expression.h +@@ -88,6 +88,16 @@ enum exp_opcode + when X is a pointer instead of an aggregate. */ + STRUCTOP_MPTR, + ++ /* TYPE_INSTANCE is used when the user specifies a specific ++ type instantiation for overloaded methods/functions. The format ++ is: TYPE_INSTANCE num_types type0 ... typeN num_types TYPE_INSTANCE*/ ++ TYPE_INSTANCE, ++ ++ /* TYPE_INSTANCE_LOOKUP is used when the user specifies a specific ++ type instantiation of a function (not a method). In this case, ++ we must toss the results of the parser and manually do the lookup. */ ++ TYPE_INSTANCE_LOOKUP, ++ + /* end of C++. */ + + /* For Modula-2 integer division DIV */ +@@ -426,6 +436,8 @@ enum noside + extern struct value *evaluate_subexp_standard + (struct type *, struct expression *, int *, enum noside); + ++extern int compare_parameters (struct type *, struct type *); ++ + /* From expprint.c */ + + extern void print_expression (struct expression *, struct ui_file *); +@@ -435,4 +447,5 @@ extern char *op_string (enum exp_opcode); + extern void dump_raw_expression (struct expression *, struct ui_file *, char *); + extern void dump_prefix_expression (struct expression *, struct ui_file *); + ++ + #endif /* !defined (EXPRESSION_H) */ +diff --git a/gdb/f-exp.y b/gdb/f-exp.y +index d91c413..c984e85 100644 +--- a/gdb/f-exp.y ++++ b/gdb/f-exp.y +@@ -198,6 +198,7 @@ static int parse_number (char *, int, int, YYSTYPE *); + /* Special type cases, put in to allow the parser to distinguish different + legal basetypes. */ + %token INT_KEYWORD INT_S2_KEYWORD LOGICAL_S1_KEYWORD LOGICAL_S2_KEYWORD ++%token LOGICAL_S8_KEYWORD + %token LOGICAL_KEYWORD REAL_KEYWORD REAL_S8_KEYWORD REAL_S16_KEYWORD + %token COMPLEX_S8_KEYWORD COMPLEX_S16_KEYWORD COMPLEX_S32_KEYWORD + %token BOOL_AND BOOL_OR BOOL_NOT +@@ -608,6 +609,8 @@ typebase /* Implements (approximately): (type-qualifier)* type-specifier */ + { $$ = parse_f_type->builtin_integer_s2; } + | CHARACTER + { $$ = parse_f_type->builtin_character; } ++ | LOGICAL_S8_KEYWORD ++ { $$ = parse_f_type->builtin_logical_s8;} + | LOGICAL_KEYWORD + { $$ = parse_f_type->builtin_logical; } + | LOGICAL_S2_KEYWORD +@@ -860,6 +863,7 @@ static const struct token f77_keywords[] = + { "integer_2", INT_S2_KEYWORD, BINOP_END }, + { "logical_1", LOGICAL_S1_KEYWORD, BINOP_END }, + { "logical_2", LOGICAL_S2_KEYWORD, BINOP_END }, ++ { "logical_8", LOGICAL_S8_KEYWORD, BINOP_END }, + { "complex_8", COMPLEX_S8_KEYWORD, BINOP_END }, + { "integer", INT_KEYWORD, BINOP_END }, + { "logical", LOGICAL_KEYWORD, BINOP_END }, +diff --git a/gdb/f-lang.c b/gdb/f-lang.c +index 6359841..1754c44 100644 +--- a/gdb/f-lang.c ++++ b/gdb/f-lang.c +@@ -55,23 +55,10 @@ typedef struct saved_bf_symnum SAVED_BF, *SAVED_BF_PTR; + /* Local functions */ + + extern void _initialize_f_language (void); +-#if 0 +-static void clear_function_list (void); +-static long get_bf_for_fcn (long); +-static void clear_bf_list (void); +-static void patch_all_commons_by_name (char *, CORE_ADDR, int); +-static SAVED_F77_COMMON_PTR find_first_common_named (char *); +-static void add_common_entry (struct symbol *); +-static void add_common_block (char *, CORE_ADDR, int, char *); +-static SAVED_FUNCTION *allocate_saved_function_node (void); +-static SAVED_BF_PTR allocate_saved_bf_node (void); +-static COMMON_ENTRY_PTR allocate_common_entry_node (void); +-static SAVED_F77_COMMON_PTR allocate_saved_f77_common_node (void); +-static void patch_common_entries (SAVED_F77_COMMON_PTR, CORE_ADDR, int); +-#endif +- +-static void f_printchar (int c, struct ui_file * stream); +-static void f_emit_char (int c, struct ui_file * stream, int quoter); ++ ++static void f_printchar (int c, struct type *type, struct ui_file * stream); ++static void f_emit_char (int c, struct type *type, ++ struct ui_file * stream, int quoter); + + /* Print the character C on STREAM as part of the contents of a literal + string whose delimiter is QUOTER. Note that that format for printing +@@ -80,7 +67,7 @@ static void f_emit_char (int c, struct ui_file * stream, int quoter); + be replaced with a true F77 version. */ + + static void +-f_emit_char (int c, struct ui_file *stream, int quoter) ++f_emit_char (int c, struct type *type, struct ui_file *stream, int quoter) + { + c &= 0xFF; /* Avoid sign bit follies */ + +@@ -126,10 +113,10 @@ f_emit_char (int c, struct ui_file *stream, int quoter) + be replaced with a true F77version. */ + + static void +-f_printchar (int c, struct ui_file *stream) ++f_printchar (int c, struct type *type, struct ui_file *stream) + { + fputs_filtered ("'", stream); +- LA_EMIT_CHAR (c, stream, '\''); ++ LA_EMIT_CHAR (c, type, stream, '\''); + fputs_filtered ("'", stream); + } + +@@ -141,14 +128,15 @@ f_printchar (int c, struct ui_file *stream) + be replaced with a true F77 version. */ + + static void +-f_printstr (struct ui_file *stream, const gdb_byte *string, +- unsigned int length, int width, int force_ellipses, ++f_printstr (struct ui_file *stream, struct type *type, const gdb_byte *string, ++ unsigned int length, int force_ellipses, + const struct value_print_options *options) + { + unsigned int i; + unsigned int things_printed = 0; + int in_quotes = 0; + int need_comma = 0; ++ int width = TYPE_LENGTH (type); + + if (length == 0) + { +@@ -190,7 +178,7 @@ f_printstr (struct ui_file *stream, const gdb_byte *string, + fputs_filtered ("', ", stream); + in_quotes = 0; + } +- f_printchar (string[i], stream); ++ f_printchar (string[i], type, stream); + fprintf_filtered (stream, " ", reps); + i = rep1 - 1; + things_printed += options->repeat_count_threshold; +@@ -206,7 +194,7 @@ f_printstr (struct ui_file *stream, const gdb_byte *string, + fputs_filtered ("'", stream); + in_quotes = 1; + } +- LA_EMIT_CHAR (string[i], stream, '"'); ++ LA_EMIT_CHAR (string[i], type, stream, '"'); + ++things_printed; + } + } +@@ -257,6 +245,7 @@ enum f_primitive_types { + f_primitive_type_logical, + f_primitive_type_logical_s1, + f_primitive_type_logical_s2, ++ f_primitive_type_logical_s8, + f_primitive_type_integer, + f_primitive_type_integer_s2, + f_primitive_type_real, +@@ -287,6 +276,8 @@ f_language_arch_info (struct gdbarch *gdbarch, + = builtin->builtin_logical_s1; + lai->primitive_type_vector [f_primitive_type_logical_s2] + = builtin->builtin_logical_s2; ++ lai->primitive_type_vector [f_primitive_type_logical_s8] ++ = builtin->builtin_logical_s8; + lai->primitive_type_vector [f_primitive_type_real] + = builtin->builtin_real; + lai->primitive_type_vector [f_primitive_type_real_s8] +@@ -378,6 +369,11 @@ build_fortran_types (struct gdbarch *gdbarch) + gdbarch_short_bit (gdbarch) / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, "logical*2", (struct objfile *) NULL); + ++ builtin_f_type->builtin_logical_s8 = ++ init_type (TYPE_CODE_BOOL, ++ gdbarch_long_long_bit (gdbarch) / TARGET_CHAR_BIT, ++ TYPE_FLAG_UNSIGNED, "logical*8", (struct objfile *) NULL); ++ + builtin_f_type->builtin_integer = + init_type (TYPE_CODE_INT, + gdbarch_int_bit (gdbarch) / TARGET_CHAR_BIT, +@@ -451,395 +447,3 @@ _initialize_f_language (void) + + add_language (&f_language_defn); + } +- +-#if 0 +-static SAVED_BF_PTR +-allocate_saved_bf_node (void) +-{ +- SAVED_BF_PTR new; +- +- new = (SAVED_BF_PTR) xmalloc (sizeof (SAVED_BF)); +- return (new); +-} +- +-static SAVED_FUNCTION * +-allocate_saved_function_node (void) +-{ +- SAVED_FUNCTION *new; +- +- new = (SAVED_FUNCTION *) xmalloc (sizeof (SAVED_FUNCTION)); +- return (new); +-} +- +-static SAVED_F77_COMMON_PTR +-allocate_saved_f77_common_node (void) +-{ +- SAVED_F77_COMMON_PTR new; +- +- new = (SAVED_F77_COMMON_PTR) xmalloc (sizeof (SAVED_F77_COMMON)); +- return (new); +-} +- +-static COMMON_ENTRY_PTR +-allocate_common_entry_node (void) +-{ +- COMMON_ENTRY_PTR new; +- +- new = (COMMON_ENTRY_PTR) xmalloc (sizeof (COMMON_ENTRY)); +- return (new); +-} +-#endif +- +-SAVED_F77_COMMON_PTR head_common_list = NULL; /* Ptr to 1st saved COMMON */ +-SAVED_F77_COMMON_PTR tail_common_list = NULL; /* Ptr to last saved COMMON */ +-SAVED_F77_COMMON_PTR current_common = NULL; /* Ptr to current COMMON */ +- +-#if 0 +-static SAVED_BF_PTR saved_bf_list = NULL; /* Ptr to (.bf,function) +- list */ +-static SAVED_BF_PTR saved_bf_list_end = NULL; /* Ptr to above list's end */ +-static SAVED_BF_PTR current_head_bf_list = NULL; /* Current head of above list +- */ +- +-static SAVED_BF_PTR tmp_bf_ptr; /* Generic temporary for use +- in macros */ +- +-/* The following function simply enters a given common block onto +- the global common block chain */ +- +-static void +-add_common_block (char *name, CORE_ADDR offset, int secnum, char *func_stab) +-{ +- SAVED_F77_COMMON_PTR tmp; +- char *c, *local_copy_func_stab; +- +- /* If the COMMON block we are trying to add has a blank +- name (i.e. "#BLNK_COM") then we set it to __BLANK +- because the darn "#" character makes GDB's input +- parser have fits. */ +- +- +- if (strcmp (name, BLANK_COMMON_NAME_ORIGINAL) == 0 +- || strcmp (name, BLANK_COMMON_NAME_MF77) == 0) +- { +- +- xfree (name); +- name = alloca (strlen (BLANK_COMMON_NAME_LOCAL) + 1); +- strcpy (name, BLANK_COMMON_NAME_LOCAL); +- } +- +- tmp = allocate_saved_f77_common_node (); +- +- local_copy_func_stab = xmalloc (strlen (func_stab) + 1); +- strcpy (local_copy_func_stab, func_stab); +- +- tmp->name = xmalloc (strlen (name) + 1); +- +- /* local_copy_func_stab is a stabstring, let us first extract the +- function name from the stab by NULLing out the ':' character. */ +- +- +- c = NULL; +- c = strchr (local_copy_func_stab, ':'); +- +- if (c) +- *c = '\0'; +- else +- error (_("Malformed function STAB found in add_common_block()")); +- +- +- tmp->owning_function = xmalloc (strlen (local_copy_func_stab) + 1); +- +- strcpy (tmp->owning_function, local_copy_func_stab); +- +- strcpy (tmp->name, name); +- tmp->offset = offset; +- tmp->next = NULL; +- tmp->entries = NULL; +- tmp->secnum = secnum; +- +- current_common = tmp; +- +- if (head_common_list == NULL) +- { +- head_common_list = tail_common_list = tmp; +- } +- else +- { +- tail_common_list->next = tmp; +- tail_common_list = tmp; +- } +-} +-#endif +- +-/* The following function simply enters a given common entry onto +- the "current_common" block that has been saved away. */ +- +-#if 0 +-static void +-add_common_entry (struct symbol *entry_sym_ptr) +-{ +- COMMON_ENTRY_PTR tmp; +- +- +- +- /* The order of this list is important, since +- we expect the entries to appear in decl. +- order when we later issue "info common" calls */ +- +- tmp = allocate_common_entry_node (); +- +- tmp->next = NULL; +- tmp->symbol = entry_sym_ptr; +- +- if (current_common == NULL) +- error (_("Attempt to add COMMON entry with no block open!")); +- else +- { +- if (current_common->entries == NULL) +- { +- current_common->entries = tmp; +- current_common->end_of_entries = tmp; +- } +- else +- { +- current_common->end_of_entries->next = tmp; +- current_common->end_of_entries = tmp; +- } +- } +-} +-#endif +- +-/* This routine finds the first encountred COMMON block named "name" */ +- +-#if 0 +-static SAVED_F77_COMMON_PTR +-find_first_common_named (char *name) +-{ +- +- SAVED_F77_COMMON_PTR tmp; +- +- tmp = head_common_list; +- +- while (tmp != NULL) +- { +- if (strcmp (tmp->name, name) == 0) +- return (tmp); +- else +- tmp = tmp->next; +- } +- return (NULL); +-} +-#endif +- +-/* This routine finds the first encountred COMMON block named "name" +- that belongs to function funcname */ +- +-SAVED_F77_COMMON_PTR +-find_common_for_function (char *name, char *funcname) +-{ +- +- SAVED_F77_COMMON_PTR tmp; +- +- tmp = head_common_list; +- +- while (tmp != NULL) +- { +- if (strcmp (tmp->name, name) == 0 +- && strcmp (tmp->owning_function, funcname) == 0) +- return (tmp); +- else +- tmp = tmp->next; +- } +- return (NULL); +-} +- +- +-#if 0 +- +-/* The following function is called to patch up the offsets +- for the statics contained in the COMMON block named +- "name." */ +- +-static void +-patch_common_entries (SAVED_F77_COMMON_PTR blk, CORE_ADDR offset, int secnum) +-{ +- COMMON_ENTRY_PTR entry; +- +- blk->offset = offset; /* Keep this around for future use. */ +- +- entry = blk->entries; +- +- while (entry != NULL) +- { +- SYMBOL_VALUE (entry->symbol) += offset; +- SYMBOL_SECTION (entry->symbol) = secnum; +- +- entry = entry->next; +- } +- blk->secnum = secnum; +-} +- +-/* Patch all commons named "name" that need patching.Since COMMON +- blocks occur with relative infrequency, we simply do a linear scan on +- the name. Eventually, the best way to do this will be a +- hashed-lookup. Secnum is the section number for the .bss section +- (which is where common data lives). */ +- +-static void +-patch_all_commons_by_name (char *name, CORE_ADDR offset, int secnum) +-{ +- +- SAVED_F77_COMMON_PTR tmp; +- +- /* For blank common blocks, change the canonical reprsentation +- of a blank name */ +- +- if (strcmp (name, BLANK_COMMON_NAME_ORIGINAL) == 0 +- || strcmp (name, BLANK_COMMON_NAME_MF77) == 0) +- { +- xfree (name); +- name = alloca (strlen (BLANK_COMMON_NAME_LOCAL) + 1); +- strcpy (name, BLANK_COMMON_NAME_LOCAL); +- } +- +- tmp = head_common_list; +- +- while (tmp != NULL) +- { +- if (COMMON_NEEDS_PATCHING (tmp)) +- if (strcmp (tmp->name, name) == 0) +- patch_common_entries (tmp, offset, secnum); +- +- tmp = tmp->next; +- } +-} +-#endif +- +-/* This macro adds the symbol-number for the start of the function +- (the symbol number of the .bf) referenced by symnum_fcn to a +- list. This list, in reality should be a FIFO queue but since +- #line pragmas sometimes cause line ranges to get messed up +- we simply create a linear list. This list can then be searched +- first by a queueing algorithm and upon failure fall back to +- a linear scan. */ +- +-#if 0 +-#define ADD_BF_SYMNUM(bf_sym,fcn_sym) \ +- \ +- if (saved_bf_list == NULL) \ +-{ \ +- tmp_bf_ptr = allocate_saved_bf_node(); \ +- \ +- tmp_bf_ptr->symnum_bf = (bf_sym); \ +- tmp_bf_ptr->symnum_fcn = (fcn_sym); \ +- tmp_bf_ptr->next = NULL; \ +- \ +- current_head_bf_list = saved_bf_list = tmp_bf_ptr; \ +- saved_bf_list_end = tmp_bf_ptr; \ +- } \ +-else \ +-{ \ +- tmp_bf_ptr = allocate_saved_bf_node(); \ +- \ +- tmp_bf_ptr->symnum_bf = (bf_sym); \ +- tmp_bf_ptr->symnum_fcn = (fcn_sym); \ +- tmp_bf_ptr->next = NULL; \ +- \ +- saved_bf_list_end->next = tmp_bf_ptr; \ +- saved_bf_list_end = tmp_bf_ptr; \ +- } +-#endif +- +-/* This function frees the entire (.bf,function) list */ +- +-#if 0 +-static void +-clear_bf_list (void) +-{ +- +- SAVED_BF_PTR tmp = saved_bf_list; +- SAVED_BF_PTR next = NULL; +- +- while (tmp != NULL) +- { +- next = tmp->next; +- xfree (tmp); +- tmp = next; +- } +- saved_bf_list = NULL; +-} +-#endif +- +-int global_remote_debug; +- +-#if 0 +- +-static long +-get_bf_for_fcn (long the_function) +-{ +- SAVED_BF_PTR tmp; +- int nprobes = 0; +- +- /* First use a simple queuing algorithm (i.e. look and see if the +- item at the head of the queue is the one you want) */ +- +- if (saved_bf_list == NULL) +- internal_error (__FILE__, __LINE__, +- _("cannot get .bf node off empty list")); +- +- if (current_head_bf_list != NULL) +- if (current_head_bf_list->symnum_fcn == the_function) +- { +- if (global_remote_debug) +- fprintf_unfiltered (gdb_stderr, "*"); +- +- tmp = current_head_bf_list; +- current_head_bf_list = current_head_bf_list->next; +- return (tmp->symnum_bf); +- } +- +- /* If the above did not work (probably because #line directives were +- used in the sourcefile and they messed up our internal tables) we now do +- the ugly linear scan */ +- +- if (global_remote_debug) +- fprintf_unfiltered (gdb_stderr, "\ndefaulting to linear scan\n"); +- +- nprobes = 0; +- tmp = saved_bf_list; +- while (tmp != NULL) +- { +- nprobes++; +- if (tmp->symnum_fcn == the_function) +- { +- if (global_remote_debug) +- fprintf_unfiltered (gdb_stderr, "Found in %d probes\n", nprobes); +- current_head_bf_list = tmp->next; +- return (tmp->symnum_bf); +- } +- tmp = tmp->next; +- } +- +- return (-1); +-} +- +-static SAVED_FUNCTION_PTR saved_function_list = NULL; +-static SAVED_FUNCTION_PTR saved_function_list_end = NULL; +- +-static void +-clear_function_list (void) +-{ +- SAVED_FUNCTION_PTR tmp = saved_function_list; +- SAVED_FUNCTION_PTR next = NULL; +- +- while (tmp != NULL) +- { +- next = tmp->next; +- xfree (tmp); +- tmp = next; +- } +- +- saved_function_list = NULL; +-} +-#endif +diff --git a/gdb/f-lang.h b/gdb/f-lang.h +index 711bdba..cd2f804 100644 +--- a/gdb/f-lang.h ++++ b/gdb/f-lang.h +@@ -28,6 +28,10 @@ extern void f_error (char *); /* Defined in f-exp.y */ + extern void f_print_type (struct type *, char *, struct ui_file *, int, + int); + ++extern const char *f_object_address_data_valid_print_to_stream ++ (struct type *type, struct ui_file *stream); ++extern void f_object_address_data_valid_or_error (struct type *type); ++ + extern int f_val_print (struct type *, const gdb_byte *, int, CORE_ADDR, + struct ui_file *, int, + const struct value_print_options *); +@@ -47,41 +51,8 @@ enum f90_range_type + NONE_BOUND_DEFAULT /* "(low:high)" */ + }; + +-struct common_entry +- { +- struct symbol *symbol; /* The symbol node corresponding +- to this component */ +- struct common_entry *next; /* The next component */ +- }; +- +-struct saved_f77_common +- { +- char *name; /* Name of COMMON */ +- char *owning_function; /* Name of parent function */ +- int secnum; /* Section # of .bss */ +- CORE_ADDR offset; /* Offset from .bss for +- this block */ +- struct common_entry *entries; /* List of block's components */ +- struct common_entry *end_of_entries; /* ptr. to end of components */ +- struct saved_f77_common *next; /* Next saved COMMON block */ +- }; +- +-typedef struct saved_f77_common SAVED_F77_COMMON, *SAVED_F77_COMMON_PTR; +- +-typedef struct common_entry COMMON_ENTRY, *COMMON_ENTRY_PTR; +- +-extern SAVED_F77_COMMON_PTR head_common_list; /* Ptr to 1st saved COMMON */ +-extern SAVED_F77_COMMON_PTR tail_common_list; /* Ptr to last saved COMMON */ +-extern SAVED_F77_COMMON_PTR current_common; /* Ptr to current COMMON */ +- +-extern SAVED_F77_COMMON_PTR find_common_for_function (char *, char *); +- +-#define UNINITIALIZED_SECNUM -1 +-#define COMMON_NEEDS_PATCHING(blk) ((blk)->secnum == UNINITIALIZED_SECNUM) +- + #define BLANK_COMMON_NAME_ORIGINAL "#BLNK_COM" /* XLF assigned */ + #define BLANK_COMMON_NAME_MF77 "__BLNK__" /* MF77 assigned */ +-#define BLANK_COMMON_NAME_LOCAL "__BLANK" /* Local GDB */ + + /* When reasonable array bounds cannot be fetched, such as when + you ask to 'mt print symbols' and there is no stack frame and +@@ -113,6 +84,7 @@ struct builtin_f_type + struct type *builtin_logical; + struct type *builtin_logical_s1; + struct type *builtin_logical_s2; ++ struct type *builtin_logical_s8; + struct type *builtin_real; + struct type *builtin_real_s8; + struct type *builtin_real_s16; +diff --git a/gdb/f-typeprint.c b/gdb/f-typeprint.c +index 6c9668f..852b9a8 100644 +--- a/gdb/f-typeprint.c ++++ b/gdb/f-typeprint.c +@@ -31,7 +31,7 @@ + #include "gdbcore.h" + #include "target.h" + #include "f-lang.h" +- ++#include "dwarf2loc.h" + #include "gdb_string.h" + #include + +@@ -48,6 +48,34 @@ void f_type_print_varspec_prefix (struct type *, struct ui_file *, + void f_type_print_base (struct type *, struct ui_file *, int, int); + + ++const char * ++f_object_address_data_valid_print_to_stream (struct type *type, ++ struct ui_file *stream) ++{ ++ const char *msg; ++ ++ msg = object_address_data_not_valid (type); ++ if (msg != NULL) ++ { ++ /* Assuming the content printed to STREAM should not be localized. */ ++ fprintf_filtered (stream, "<%s>", msg); ++ } ++ ++ return msg; ++} ++ ++void ++f_object_address_data_valid_or_error (struct type *type) ++{ ++ const char *msg; ++ ++ msg = object_address_data_not_valid (type); ++ if (msg != NULL) ++ { ++ error (_("Cannot access it because the %s."), _(msg)); ++ } ++} ++ + /* LEVEL is the depth to indent lines by. */ + + void +@@ -57,6 +85,9 @@ f_print_type (struct type *type, char *varstring, struct ui_file *stream, + enum type_code code; + int demangled_args; + ++ if (f_object_address_data_valid_print_to_stream (type, stream) != NULL) ++ return; ++ + f_type_print_base (type, stream, show, level); + code = TYPE_CODE (type); + if ((varstring != NULL && *varstring != '\0') +@@ -166,6 +197,9 @@ f_type_print_varspec_suffix (struct type *type, struct ui_file *stream, + + QUIT; + ++ if (TYPE_CODE (type) != TYPE_CODE_TYPEDEF) ++ CHECK_TYPEDEF (type); ++ + switch (TYPE_CODE (type)) + { + case TYPE_CODE_ARRAY: +diff --git a/gdb/f-valprint.c b/gdb/f-valprint.c +index 5721041..2cff7bc 100644 +--- a/gdb/f-valprint.c ++++ b/gdb/f-valprint.c +@@ -34,10 +34,8 @@ + #include "gdbcore.h" + #include "command.h" + #include "block.h" +- +-#if 0 +-static int there_is_a_visible_common_named (char *); +-#endif ++#include "dictionary.h" ++#include "gdb_assert.h" + + extern void _initialize_f_valprint (void); + static void info_common_command (char *, int); +@@ -54,15 +52,17 @@ int f77_array_offset_tbl[MAX_FORTRAN_DIMS + 1][2]; + /* The following macro gives us the size of the nth dimension, Where + n is 1 based. */ + +-#define F77_DIM_SIZE(n) (f77_array_offset_tbl[n][1]) ++#define F77_DIM_COUNT(n) (f77_array_offset_tbl[n][1]) + +-/* The following gives us the offset for row n where n is 1-based. */ ++/* The following gives us the element size for row n where n is 1-based. */ + +-#define F77_DIM_OFFSET(n) (f77_array_offset_tbl[n][0]) ++#define F77_DIM_BYTE_STRIDE(n) (f77_array_offset_tbl[n][0]) + + int + f77_get_lowerbound (struct type *type) + { ++ f_object_address_data_valid_or_error (type); ++ + if (TYPE_ARRAY_LOWER_BOUND_IS_UNDEFINED (type)) + error (_("Lower bound may not be '*' in F77")); + +@@ -72,14 +72,17 @@ f77_get_lowerbound (struct type *type) + int + f77_get_upperbound (struct type *type) + { ++ f_object_address_data_valid_or_error (type); ++ + if (TYPE_ARRAY_UPPER_BOUND_IS_UNDEFINED (type)) + { +- /* We have an assumed size array on our hands. Assume that +- upper_bound == lower_bound so that we show at least 1 element. +- If the user wants to see more elements, let him manually ask for 'em +- and we'll subscript the array and show him. */ ++ /* We have an assumed size array on our hands. As type_length_get ++ already assumes a length zero of arrays with underfined bounds VALADDR ++ passed to the Fortran functions does not contained the real inferior ++ memory content. User should request printing of specific array ++ elements instead. */ + +- return f77_get_lowerbound (type); ++ return f77_get_lowerbound (type) - 1; + } + + return TYPE_ARRAY_UPPER_BOUND_VALUE (type); +@@ -135,24 +138,29 @@ f77_create_arrayprint_offset_tbl (struct type *type, struct ui_file *stream) + upper = f77_get_upperbound (tmp_type); + lower = f77_get_lowerbound (tmp_type); + +- F77_DIM_SIZE (ndimen) = upper - lower + 1; ++ F77_DIM_COUNT (ndimen) = upper - lower + 1; ++ ++ F77_DIM_BYTE_STRIDE (ndimen) = ++ TYPE_ARRAY_BYTE_STRIDE_VALUE (tmp_type); + + tmp_type = TYPE_TARGET_TYPE (tmp_type); + ndimen++; + } + +- /* Now we multiply eltlen by all the offsets, so that later we ++ /* Now we multiply eltlen by all the BYTE_STRIDEs, so that later we + can print out array elements correctly. Up till now we +- know an offset to apply to get the item but we also ++ know an eltlen to apply to get the item but we also + have to know how much to add to get to the next item */ + + ndimen--; + eltlen = TYPE_LENGTH (tmp_type); +- F77_DIM_OFFSET (ndimen) = eltlen; ++ if (F77_DIM_BYTE_STRIDE (ndimen) == 0) ++ F77_DIM_BYTE_STRIDE (ndimen) = eltlen; + while (--ndimen > 0) + { +- eltlen *= F77_DIM_SIZE (ndimen + 1); +- F77_DIM_OFFSET (ndimen) = eltlen; ++ eltlen *= F77_DIM_COUNT (ndimen + 1); ++ if (F77_DIM_BYTE_STRIDE (ndimen) == 0) ++ F77_DIM_BYTE_STRIDE (ndimen) = eltlen; + } + } + +@@ -172,34 +180,34 @@ f77_print_array_1 (int nss, int ndimensions, struct type *type, + + if (nss != ndimensions) + { +- for (i = 0; (i < F77_DIM_SIZE (nss) && (*elts) < options->print_max); i++) ++ for (i = 0; (i < F77_DIM_COUNT (nss) && (*elts) < options->print_max); i++) + { + fprintf_filtered (stream, "( "); + f77_print_array_1 (nss + 1, ndimensions, TYPE_TARGET_TYPE (type), +- valaddr + i * F77_DIM_OFFSET (nss), +- address + i * F77_DIM_OFFSET (nss), ++ valaddr + i * F77_DIM_BYTE_STRIDE (nss), ++ address + i * F77_DIM_BYTE_STRIDE (nss), + stream, recurse, options, elts); + fprintf_filtered (stream, ") "); + } +- if (*elts >= options->print_max && i < F77_DIM_SIZE (nss)) ++ if (*elts >= options->print_max && i < F77_DIM_COUNT (nss)) + fprintf_filtered (stream, "..."); + } + else + { +- for (i = 0; i < F77_DIM_SIZE (nss) && (*elts) < options->print_max; ++ for (i = 0; i < F77_DIM_COUNT (nss) && (*elts) < options->print_max; + i++, (*elts)++) + { + val_print (TYPE_TARGET_TYPE (type), +- valaddr + i * F77_DIM_OFFSET (ndimensions), ++ valaddr + i * F77_DIM_BYTE_STRIDE (ndimensions), + 0, +- address + i * F77_DIM_OFFSET (ndimensions), ++ address + i * F77_DIM_BYTE_STRIDE (ndimensions), + stream, recurse, options, current_language); + +- if (i != (F77_DIM_SIZE (nss) - 1)) ++ if (i != (F77_DIM_COUNT (nss) - 1)) + fprintf_filtered (stream, ", "); + + if ((*elts == options->print_max - 1) +- && (i != (F77_DIM_SIZE (nss) - 1))) ++ && (i != (F77_DIM_COUNT (nss) - 1))) + fprintf_filtered (stream, "..."); + } + } +@@ -251,12 +259,16 @@ f_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, + CORE_ADDR addr; + int index; + ++ if (f_object_address_data_valid_print_to_stream (type, stream) != NULL) ++ return 0; ++ + CHECK_TYPEDEF (type); + switch (TYPE_CODE (type)) + { + case TYPE_CODE_STRING: + f77_get_dynamic_length_of_aggregate (type); +- LA_PRINT_STRING (stream, valaddr, TYPE_LENGTH (type), 1, 0, options); ++ LA_PRINT_STRING (stream, builtin_type (current_gdbarch)->builtin_char, ++ valaddr, TYPE_LENGTH (type), 0, options); + break; + + case TYPE_CODE_ARRAY: +@@ -293,7 +305,7 @@ f_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, + && TYPE_CODE (elttype) == TYPE_CODE_INT + && (options->format == 0 || options->format == 's') + && addr != 0) +- i = val_print_string (addr, -1, TYPE_LENGTH (elttype), stream, ++ i = val_print_string (TYPE_TARGET_TYPE (type), addr, -1, stream, + options); + + /* Return number of characters printed, including the terminating +@@ -365,7 +377,7 @@ f_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, + { + fputs_filtered (" ", stream); + LA_PRINT_CHAR ((unsigned char) unpack_long (type, valaddr), +- stream); ++ type, stream); + } + } + break; +@@ -464,22 +476,54 @@ f_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, + return 0; + } + +-static void +-list_all_visible_commons (char *funname) ++static int ++info_common_command_for_block (struct block *block, struct frame_info *frame, ++ const char *comname) + { +- SAVED_F77_COMMON_PTR tmp; +- +- tmp = head_common_list; +- +- printf_filtered (_("All COMMON blocks visible at this level:\n\n")); +- +- while (tmp != NULL) +- { +- if (strcmp (tmp->owning_function, funname) == 0) +- printf_filtered ("%s\n", tmp->name); +- +- tmp = tmp->next; +- } ++ struct dict_iterator iter; ++ struct symbol *sym; ++ int values_printed = 0; ++ const char *name; ++ struct value_print_options opts; ++ ++ get_user_print_options (&opts); ++ ++ ALL_BLOCK_SYMBOLS (block, iter, sym) ++ if (SYMBOL_DOMAIN (sym) == COMMON_BLOCK_DOMAIN) ++ { ++ struct type *type = SYMBOL_TYPE (sym); ++ int index; ++ ++ gdb_assert (SYMBOL_CLASS (sym) == LOC_STATIC); ++ gdb_assert (TYPE_CODE (type) == TYPE_CODE_STRUCT); ++ ++ if (comname && (!SYMBOL_LINKAGE_NAME (sym) ++ || strcmp (comname, SYMBOL_LINKAGE_NAME (sym)) != 0)) ++ continue; ++ ++ values_printed = 1; ++ if (SYMBOL_PRINT_NAME (sym)) ++ printf_filtered (_("Contents of F77 COMMON block '%s':\n"), ++ SYMBOL_PRINT_NAME (sym)); ++ else ++ printf_filtered (_("Contents of blank COMMON block:\n")); ++ ++ for (index = 0; index < TYPE_NFIELDS (type); index++) ++ { ++ struct value *val; ++ ++ gdb_assert (field_is_static (&TYPE_FIELD (type, index))); ++ val = value_static_field (type, index); ++ ++ printf_filtered ("%s = ", TYPE_FIELD_NAME (type, index)); ++ value_print (val, gdb_stdout, &opts); ++ putchar_filtered ('\n'); ++ } ++ ++ putchar_filtered ('\n'); ++ } ++ ++ return values_printed; + } + + /* This function is used to print out the values in a given COMMON +@@ -489,11 +533,9 @@ list_all_visible_commons (char *funname) + static void + info_common_command (char *comname, int from_tty) + { +- SAVED_F77_COMMON_PTR the_common; +- COMMON_ENTRY_PTR entry; + struct frame_info *fi; +- char *funname = 0; +- struct symbol *func; ++ struct block *block; ++ int values_printed = 0; + + /* We have been told to display the contents of F77 COMMON + block supposedly visible in this function. Let us +@@ -505,136 +547,32 @@ info_common_command (char *comname, int from_tty) + /* The following is generally ripped off from stack.c's routine + print_frame_info() */ + +- func = find_pc_function (get_frame_pc (fi)); +- if (func) +- { +- /* In certain pathological cases, the symtabs give the wrong +- function (when we are in the first function in a file which +- is compiled without debugging symbols, the previous function +- is compiled with debugging symbols, and the "foo.o" symbol +- that is supposed to tell us where the file with debugging symbols +- ends has been truncated by ar because it is longer than 15 +- characters). +- +- So look in the minimal symbol tables as well, and if it comes +- up with a larger address for the function use that instead. +- I don't think this can ever cause any problems; there shouldn't +- be any minimal symbols in the middle of a function. +- FIXME: (Not necessarily true. What about text labels) */ +- +- struct minimal_symbol *msymbol = +- lookup_minimal_symbol_by_pc (get_frame_pc (fi)); +- +- if (msymbol != NULL +- && (SYMBOL_VALUE_ADDRESS (msymbol) +- > BLOCK_START (SYMBOL_BLOCK_VALUE (func)))) +- funname = SYMBOL_LINKAGE_NAME (msymbol); +- else +- funname = SYMBOL_LINKAGE_NAME (func); +- } +- else +- { +- struct minimal_symbol *msymbol = +- lookup_minimal_symbol_by_pc (get_frame_pc (fi)); +- +- if (msymbol != NULL) +- funname = SYMBOL_LINKAGE_NAME (msymbol); +- else /* Got no 'funname', code below will fail. */ +- error (_("No function found for frame.")); +- } +- +- /* If comname is NULL, we assume the user wishes to see the +- which COMMON blocks are visible here and then return */ +- +- if (comname == 0) ++ block = get_frame_block (fi, 0); ++ if (block == NULL) + { +- list_all_visible_commons (funname); ++ printf_filtered (_("No symbol table info available.\n")); + return; + } + +- the_common = find_common_for_function (comname, funname); +- +- if (the_common) ++ while (block) + { +- if (strcmp (comname, BLANK_COMMON_NAME_LOCAL) == 0) +- printf_filtered (_("Contents of blank COMMON block:\n")); +- else +- printf_filtered (_("Contents of F77 COMMON block '%s':\n"), comname); +- +- printf_filtered ("\n"); +- entry = the_common->entries; +- +- while (entry != NULL) +- { +- print_variable_and_value (NULL, entry->symbol, fi, gdb_stdout, 0); +- entry = entry->next; +- } ++ if (info_common_command_for_block (block, fi, comname)) ++ values_printed = 1; ++ /* After handling the function's top-level block, stop. Don't ++ continue to its superblock, the block of per-file symbols. */ ++ if (BLOCK_FUNCTION (block)) ++ break; ++ block = BLOCK_SUPERBLOCK (block); + } +- else +- printf_filtered (_("Cannot locate the common block %s in function '%s'\n"), +- comname, funname); +-} +- +-/* This function is used to determine whether there is a +- F77 common block visible at the current scope called 'comname'. */ +- +-#if 0 +-static int +-there_is_a_visible_common_named (char *comname) +-{ +- SAVED_F77_COMMON_PTR the_common; +- struct frame_info *fi; +- char *funname = 0; +- struct symbol *func; +- +- if (comname == NULL) +- error (_("Cannot deal with NULL common name!")); + +- fi = get_selected_frame (_("No frame selected")); +- +- /* The following is generally ripped off from stack.c's routine +- print_frame_info() */ +- +- func = find_pc_function (fi->pc); +- if (func) ++ if (!values_printed) + { +- /* In certain pathological cases, the symtabs give the wrong +- function (when we are in the first function in a file which +- is compiled without debugging symbols, the previous function +- is compiled with debugging symbols, and the "foo.o" symbol +- that is supposed to tell us where the file with debugging symbols +- ends has been truncated by ar because it is longer than 15 +- characters). +- +- So look in the minimal symbol tables as well, and if it comes +- up with a larger address for the function use that instead. +- I don't think this can ever cause any problems; there shouldn't +- be any minimal symbols in the middle of a function. +- FIXME: (Not necessarily true. What about text labels) */ +- +- struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (fi->pc); +- +- if (msymbol != NULL +- && (SYMBOL_VALUE_ADDRESS (msymbol) +- > BLOCK_START (SYMBOL_BLOCK_VALUE (func)))) +- funname = SYMBOL_LINKAGE_NAME (msymbol); ++ if (comname) ++ printf_filtered (_("No common block '%s'.\n"), comname); + else +- funname = SYMBOL_LINKAGE_NAME (func); ++ printf_filtered (_("No common blocks.\n")); + } +- else +- { +- struct minimal_symbol *msymbol = +- lookup_minimal_symbol_by_pc (fi->pc); +- +- if (msymbol != NULL) +- funname = SYMBOL_LINKAGE_NAME (msymbol); +- } +- +- the_common = find_common_for_function (comname, funname); +- +- return (the_common ? 1 : 0); + } +-#endif + + void + _initialize_f_valprint (void) +diff --git a/gdb/findcmd.c b/gdb/findcmd.c +index 7ae43e5..2894948 100644 +--- a/gdb/findcmd.c ++++ b/gdb/findcmd.c +@@ -26,7 +26,7 @@ + + /* Copied from bfd_put_bits. */ + +-static void ++void + put_bits (bfd_uint64_t data, char *buf, int bits, bfd_boolean big_p) + { + int i; +@@ -44,6 +44,41 @@ put_bits (bfd_uint64_t data, char *buf, int bits, bfd_boolean big_p) + } + } + ++/* Allocates a buffer in *PATTERN_BUF, with a hard-coded initial size which ++ will be returned in *PATTERN_BUF_SIZE. *PATTERN_BUF_END points to the same ++ place as *PATTERN_BUF, indicating that the buffer is initially empty. */ ++ ++void ++allocate_pattern_buffer (char **pattern_buf, char **pattern_buf_end, ++ ULONGEST *pattern_buf_size) ++{ ++#define INITIAL_PATTERN_BUF_SIZE 100 ++ *pattern_buf_size = INITIAL_PATTERN_BUF_SIZE; ++ *pattern_buf = xmalloc (*pattern_buf_size); ++ *pattern_buf_end = *pattern_buf; ++} ++ ++/* Grows *PATTERN_BUF by a factor of two if it's not large enough to hold ++ VAL_BYTES more bytes or a 64-bit value, whichever is larger. ++ *PATTERN_BUF_END is updated as necessary. */ ++ ++void ++increase_pattern_buffer (char **pattern_buf, char **pattern_buf_end, ++ ULONGEST *pattern_buf_size, int val_bytes) ++{ ++ /* Keep it simple and assume size == 'g' when watching for when we ++ need to grow the pattern buf. */ ++ if ((*pattern_buf_end - *pattern_buf + max (val_bytes, sizeof (int64_t))) ++ > *pattern_buf_size) ++ { ++ size_t current_offset = *pattern_buf_end - *pattern_buf; ++ ++ *pattern_buf_size *= 2; ++ *pattern_buf = xrealloc (*pattern_buf, *pattern_buf_size); ++ *pattern_buf_end = *pattern_buf + current_offset; ++ } ++} ++ + /* Subroutine of find_command to simplify it. + Parse the arguments of the "find" command. */ + +@@ -59,8 +94,7 @@ parse_find_args (char *args, ULONGEST *max_countp, + char *pattern_buf; + /* Current size of search pattern buffer. + We realloc space as needed. */ +-#define INITIAL_PATTERN_BUF_SIZE 100 +- ULONGEST pattern_buf_size = INITIAL_PATTERN_BUF_SIZE; ++ ULONGEST pattern_buf_size; + /* Pointer to one past the last in-use part of pattern_buf. */ + char *pattern_buf_end; + ULONGEST pattern_len; +@@ -74,8 +108,7 @@ parse_find_args (char *args, ULONGEST *max_countp, + if (args == NULL) + error (_("Missing search parameters.")); + +- pattern_buf = xmalloc (pattern_buf_size); +- pattern_buf_end = pattern_buf; ++ allocate_pattern_buffer (&pattern_buf, &pattern_buf_end, &pattern_buf_size); + old_cleanups = make_cleanup (free_current_contents, &pattern_buf); + + /* Get search granularity and/or max count if specified. +@@ -172,16 +205,8 @@ parse_find_args (char *args, ULONGEST *max_countp, + v = parse_to_comma_and_eval (&s); + val_bytes = TYPE_LENGTH (value_type (v)); + +- /* Keep it simple and assume size == 'g' when watching for when we +- need to grow the pattern buf. */ +- if ((pattern_buf_end - pattern_buf + max (val_bytes, sizeof (int64_t))) +- > pattern_buf_size) +- { +- size_t current_offset = pattern_buf_end - pattern_buf; +- pattern_buf_size *= 2; +- pattern_buf = xrealloc (pattern_buf, pattern_buf_size); +- pattern_buf_end = pattern_buf + current_offset; +- } ++ increase_pattern_buffer (&pattern_buf, &pattern_buf_end, ++ &pattern_buf_size, val_bytes); + + if (size != '\0') + { +@@ -236,6 +261,45 @@ parse_find_args (char *args, ULONGEST *max_countp, + discard_cleanups (old_cleanups); + } + ++/* Drives target_search_memory to sweep through the specified search space, ++ possibly in several iterations (with one call to this function for each ++ iteration). *START_ADDR is the address where the search starts, and is ++ updated to the next starting address to continue the search. ++ *SEARCH_SPACE_LEN is the amount of bytes which will be searched, and is ++ updated for the next iteration. PATTERN_BUF holds the pattern to be searched ++ for, PATTERN_LEN is the size of the pattern in bytes. If a match is found, ++ it's address is put in *FOUND_ADDR. ++ ++ Returns 1 if found, 0 if not found, and -1 if there was an error requiring ++ halting of the search (e.g. memory read error). */ ++ ++int ++search_memory (CORE_ADDR *start_addr, ULONGEST *search_space_len, ++ const char *pattern_buf, ULONGEST pattern_len, ++ CORE_ADDR *found_addr) ++{ ++ /* Offset from start of this iteration to the next iteration. */ ++ ULONGEST next_iter_incr; ++ int found; ++ ++ found = target_search_memory (*start_addr, *search_space_len, ++ pattern_buf, pattern_len, found_addr); ++ if (found <= 0) ++ return found; ++ ++ /* Begin next iteration at one byte past this match. */ ++ next_iter_incr = (*found_addr - *start_addr) + 1; ++ ++ /* For robustness, we don't let search_space_len go -ve here. */ ++ if (*search_space_len >= next_iter_incr) ++ *search_space_len -= next_iter_incr; ++ else ++ *search_space_len = 0; ++ *start_addr += next_iter_incr; ++ ++ return found; ++} ++ + static void + find_command (char *args, int from_tty) + { +@@ -264,12 +328,11 @@ find_command (char *args, int from_tty) + while (search_space_len >= pattern_len + && found_count < max_count) + { +- /* Offset from start of this iteration to the next iteration. */ +- ULONGEST next_iter_incr; + CORE_ADDR found_addr; +- int found = target_search_memory (start_addr, search_space_len, +- pattern_buf, pattern_len, &found_addr); ++ int found; + ++ found = search_memory (&start_addr, &search_space_len, pattern_buf, ++ pattern_len, &found_addr); + if (found <= 0) + break; + +@@ -277,16 +340,6 @@ find_command (char *args, int from_tty) + printf_filtered ("\n"); + ++found_count; + last_found_addr = found_addr; +- +- /* Begin next iteration at one byte past this match. */ +- next_iter_incr = (found_addr - start_addr) + 1; +- +- /* For robustness, we don't let search_space_len go -ve here. */ +- if (search_space_len >= next_iter_incr) +- search_space_len -= next_iter_incr; +- else +- search_space_len = 0; +- start_addr += next_iter_incr; + } + + /* Record and print the results. */ +diff --git a/gdb/findvar.c b/gdb/findvar.c +index 1048887..b958ec6 100644 +--- a/gdb/findvar.c ++++ b/gdb/findvar.c +@@ -35,6 +35,7 @@ + #include "user-regs.h" + #include "block.h" + #include "objfiles.h" ++#include "dwarf2loc.h" + + /* Basic byte-swapping routines. GDB has needed these for a long time... + All extract a target-format integer at ADDR which is LEN bytes long. */ +@@ -275,7 +276,7 @@ value_of_register (int regnum, struct frame_info *frame) + memcpy (value_contents_raw (reg_val), raw_buffer, + register_size (gdbarch, regnum)); + VALUE_LVAL (reg_val) = lval; +- VALUE_ADDRESS (reg_val) = addr; ++ set_value_address (reg_val, addr); + VALUE_REGNUM (reg_val) = regnum; + set_value_optimized_out (reg_val, optim); + VALUE_FRAME_ID (reg_val) = get_frame_id (frame); +@@ -382,27 +383,16 @@ symbol_read_needs_frame (struct symbol *sym) + /* Given a struct symbol for a variable, + and a stack frame id, read the value of the variable + and return a (pointer to a) struct value containing the value. +- If the variable cannot be found, return a zero pointer. */ ++ If the variable cannot be found, return a zero pointer. ++ We have to first find the address of the variable before allocating struct ++ value to return as its size may depend on DW_OP_PUSH_OBJECT_ADDRESS possibly ++ used by its type. */ + + struct value * + read_var_value (struct symbol *var, struct frame_info *frame) + { +- struct value *v; + struct type *type = SYMBOL_TYPE (var); + CORE_ADDR addr; +- int len; +- +- if (SYMBOL_CLASS (var) == LOC_COMPUTED +- || SYMBOL_CLASS (var) == LOC_REGISTER) +- /* These cases do not use V. */ +- v = NULL; +- else +- { +- v = allocate_value (type); +- VALUE_LVAL (v) = lval_memory; /* The most likely possibility. */ +- } +- +- len = TYPE_LENGTH (type); + + if (symbol_read_needs_frame (var)) + gdb_assert (frame); +@@ -410,31 +400,39 @@ read_var_value (struct symbol *var, struct frame_info *frame) + switch (SYMBOL_CLASS (var)) + { + case LOC_CONST: +- /* Put the constant back in target format. */ +- store_signed_integer (value_contents_raw (v), len, +- (LONGEST) SYMBOL_VALUE (var)); +- VALUE_LVAL (v) = not_lval; +- return v; ++ { ++ /* Put the constant back in target format. */ ++ struct value *v = allocate_value (type); ++ VALUE_LVAL (v) = not_lval; ++ store_signed_integer (value_contents_raw (v), TYPE_LENGTH (type), ++ (LONGEST) SYMBOL_VALUE (var)); ++ return v; ++ } + + case LOC_LABEL: +- /* Put the constant back in target format. */ +- if (overlay_debugging) +- { +- CORE_ADDR addr +- = symbol_overlayed_address (SYMBOL_VALUE_ADDRESS (var), +- SYMBOL_OBJ_SECTION (var)); +- store_typed_address (value_contents_raw (v), type, addr); +- } +- else +- store_typed_address (value_contents_raw (v), type, +- SYMBOL_VALUE_ADDRESS (var)); +- VALUE_LVAL (v) = not_lval; +- return v; ++ { ++ /* Put the constant back in target format. */ ++ struct value *v = allocate_value (type); ++ VALUE_LVAL (v) = not_lval; ++ if (overlay_debugging) ++ { ++ CORE_ADDR addr ++ = symbol_overlayed_address (SYMBOL_VALUE_ADDRESS (var), ++ SYMBOL_OBJ_SECTION (var)); ++ store_typed_address (value_contents_raw (v), type, addr); ++ } ++ else ++ store_typed_address (value_contents_raw (v), type, ++ SYMBOL_VALUE_ADDRESS (var)); ++ return v; ++ } + + case LOC_CONST_BYTES: + { +- memcpy (value_contents_raw (v), SYMBOL_VALUE_BYTES (var), len); ++ struct value *v = allocate_value (type); + VALUE_LVAL (v) = not_lval; ++ memcpy (value_contents_raw (v), SYMBOL_VALUE_BYTES (var), ++ TYPE_LENGTH (type)); + return v; + } + +@@ -476,12 +474,23 @@ read_var_value (struct symbol *var, struct frame_info *frame) + break; + + case LOC_BLOCK: +- if (overlay_debugging) +- VALUE_ADDRESS (v) = symbol_overlayed_address +- (BLOCK_START (SYMBOL_BLOCK_VALUE (var)), SYMBOL_OBJ_SECTION (var)); +- else +- VALUE_ADDRESS (v) = BLOCK_START (SYMBOL_BLOCK_VALUE (var)); +- return v; ++ { ++ CORE_ADDR addr; ++ struct value *v; ++ ++ if (overlay_debugging) ++ addr = symbol_overlayed_address ++ (BLOCK_START (SYMBOL_BLOCK_VALUE (var)), SYMBOL_OBJ_SECTION (var)); ++ else ++ addr = BLOCK_START (SYMBOL_BLOCK_VALUE (var)); ++ /* ADDR is set here for ALLOCATE_VALUE's CHECK_TYPEDEF for ++ DW_OP_push_object_address. */ ++ object_address_set (addr); ++ v = allocate_value (type); ++ VALUE_ADDRESS (v) = addr; ++ VALUE_LVAL (v) = lval_memory; ++ return v; ++ } + + case LOC_REGISTER: + case LOC_REGPARM_ADDR: +@@ -499,7 +508,6 @@ read_var_value (struct symbol *var, struct frame_info *frame) + error (_("Value of register variable not available.")); + + addr = value_as_address (regval); +- VALUE_LVAL (v) = lval_memory; + } + else + { +@@ -542,18 +550,33 @@ read_var_value (struct symbol *var, struct frame_info *frame) + break; + + case LOC_OPTIMIZED_OUT: +- VALUE_LVAL (v) = not_lval; +- set_value_optimized_out (v, 1); +- return v; ++ { ++ struct value *v = allocate_value (type); ++ ++ VALUE_LVAL (v) = not_lval; ++ set_value_optimized_out (v, 1); ++ return v; ++ } + + default: + error (_("Cannot look up value of a botched symbol.")); + break; + } + +- VALUE_ADDRESS (v) = addr; +- set_value_lazy (v, 1); +- return v; ++ { ++ struct value *v; ++ ++ /* ADDR is set here for ALLOCATE_VALUE's CHECK_TYPEDEF for ++ DW_OP_PUSH_OBJECT_ADDRESS. */ ++ object_address_set (addr); ++ v = allocate_value (type); ++ VALUE_ADDRESS (v) = addr; ++ VALUE_LVAL (v) = lval_memory; ++ ++ set_value_lazy (v, 1); ++ ++ return v; ++ } + } + + /* Install default attributes for register values. */ +@@ -590,10 +613,11 @@ struct value * + value_from_register (struct type *type, int regnum, struct frame_info *frame) + { + struct gdbarch *gdbarch = get_frame_arch (frame); +- struct type *type1 = check_typedef (type); + struct value *v; + +- if (gdbarch_convert_register_p (gdbarch, regnum, type1)) ++ type = check_typedef (type); ++ ++ if (gdbarch_convert_register_p (gdbarch, regnum, type)) + { + /* The ISA/ABI need to something weird when obtaining the + specified value from this register. It might need to +@@ -607,7 +631,7 @@ value_from_register (struct type *type, int regnum, struct frame_info *frame) + VALUE_FRAME_ID (v) = get_frame_id (frame); + VALUE_REGNUM (v) = regnum; + gdbarch_register_to_value (gdbarch, +- frame, regnum, type1, value_contents_raw (v)); ++ frame, regnum, type, value_contents_raw (v)); + } + else + { +diff --git a/gdb/frame.c b/gdb/frame.c +index dfd6b3d..2ea37c3 100644 +--- a/gdb/frame.c ++++ b/gdb/frame.c +@@ -596,7 +596,7 @@ frame_register_unwind (struct frame_info *frame, int regnum, + + *optimizedp = value_optimized_out (value); + *lvalp = VALUE_LVAL (value); +- *addrp = VALUE_ADDRESS (value); ++ *addrp = value_address (value); + *realnump = VALUE_REGNUM (value); + + if (bufferp) +@@ -682,7 +682,7 @@ frame_unwind_register_value (struct frame_info *frame, int regnum) + VALUE_REGNUM (value)); + else if (VALUE_LVAL (value) == lval_memory) + fprintf_unfiltered (gdb_stdlog, " address=0x%s", +- paddr_nz (VALUE_ADDRESS (value))); ++ paddr_nz (value_address (value))); + else + fprintf_unfiltered (gdb_stdlog, " computed"); + +diff --git a/gdb/frv-tdep.c b/gdb/frv-tdep.c +index ff387db..452f70c 100644 +--- a/gdb/frv-tdep.c ++++ b/gdb/frv-tdep.c +@@ -1230,7 +1230,7 @@ frv_push_dummy_call (struct gdbarch *gdbarch, struct value *function, + + if (typecode == TYPE_CODE_STRUCT || typecode == TYPE_CODE_UNION) + { +- store_unsigned_integer (valbuf, 4, VALUE_ADDRESS (arg)); ++ store_unsigned_integer (valbuf, 4, value_address (arg)); + typecode = TYPE_CODE_PTR; + len = 4; + val = valbuf; +diff --git a/gdb/gdb_locale.h b/gdb/gdb_locale.h +index e8ba0ea..4fa4d3d 100644 +--- a/gdb/gdb_locale.h ++++ b/gdb/gdb_locale.h +@@ -41,4 +41,8 @@ + # define N_(String) (String) + #endif + ++#ifdef HAVE_LANGINFO_CODESET ++#include ++#endif ++ + #endif /* GDB_LOCALE_H */ +diff --git a/gdb/gdb_obstack.h b/gdb/gdb_obstack.h +index 48f49cd..cd1a1d7 100644 +--- a/gdb/gdb_obstack.h ++++ b/gdb/gdb_obstack.h +@@ -45,4 +45,7 @@ + #define obstack_grow_str0(OBSTACK,STRING) \ + obstack_grow0 (OBSTACK, STRING, strlen (STRING)) + ++#define obstack_grow_wstr(OBSTACK, WSTRING) \ ++ obstack_grow (OBSTACK, WSTRING, sizeof (wchar_t) * wcslen (WSTRING)) ++ + #endif +diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c +index 3273b34..d6c737b 100644 +--- a/gdb/gdbarch.c ++++ b/gdb/gdbarch.c +@@ -243,6 +243,11 @@ struct gdbarch + gdbarch_target_signal_to_host_ftype *target_signal_to_host; + gdbarch_get_siginfo_type_ftype *get_siginfo_type; + gdbarch_record_special_symbol_ftype *record_special_symbol; ++ gdbarch_get_syscall_number_ftype *get_syscall_number; ++ gdbarch_get_syscall_by_number_ftype *get_syscall_by_number; ++ gdbarch_get_syscall_by_name_ftype *get_syscall_by_name; ++ gdbarch_get_syscall_names_ftype *get_syscall_names; ++ const char * xml_syscall_filename; + int has_global_solist; + }; + +@@ -378,6 +383,11 @@ struct gdbarch startup_gdbarch = + default_target_signal_to_host, /* target_signal_to_host */ + 0, /* get_siginfo_type */ + 0, /* record_special_symbol */ ++ 0, /* get_syscall_number */ ++ 0, /* get_syscall_by_number */ ++ 0, /* get_syscall_by_name */ ++ 0, /* get_syscall_names */ ++ 0, /* xml_syscall_filename */ + 0, /* has_global_solist */ + /* startup_gdbarch() */ + }; +@@ -634,6 +644,11 @@ verify_gdbarch (struct gdbarch *gdbarch) + /* Skip verify of target_signal_to_host, invalid_p == 0 */ + /* Skip verify of get_siginfo_type, has predicate */ + /* Skip verify of record_special_symbol, has predicate */ ++ /* Skip verify of get_syscall_number, has predicate */ ++ /* Skip verify of get_syscall_by_number, has predicate */ ++ /* Skip verify of get_syscall_by_name, has predicate */ ++ /* Skip verify of get_syscall_names, has predicate */ ++ /* Skip verify of xml_syscall_filename, invalid_p == 0 */ + /* Skip verify of has_global_solist, invalid_p == 0 */ + buf = ui_file_xstrdup (log, &dummy); + make_cleanup (xfree, buf); +@@ -859,6 +874,30 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file) + "gdbarch_dump: get_siginfo_type = <%s>\n", + host_address_to_string (gdbarch->get_siginfo_type)); + fprintf_unfiltered (file, ++ "gdbarch_dump: gdbarch_get_syscall_by_name_p() = %d\n", ++ gdbarch_get_syscall_by_name_p (gdbarch)); ++ fprintf_unfiltered (file, ++ "gdbarch_dump: get_syscall_by_name = <%s>\n", ++ host_address_to_string (gdbarch->get_syscall_by_name)); ++ fprintf_unfiltered (file, ++ "gdbarch_dump: gdbarch_get_syscall_by_number_p() = %d\n", ++ gdbarch_get_syscall_by_number_p (gdbarch)); ++ fprintf_unfiltered (file, ++ "gdbarch_dump: get_syscall_by_number = <%s>\n", ++ host_address_to_string (gdbarch->get_syscall_by_number)); ++ fprintf_unfiltered (file, ++ "gdbarch_dump: gdbarch_get_syscall_names_p() = %d\n", ++ gdbarch_get_syscall_names_p (gdbarch)); ++ fprintf_unfiltered (file, ++ "gdbarch_dump: get_syscall_names = <%s>\n", ++ host_address_to_string (gdbarch->get_syscall_names)); ++ fprintf_unfiltered (file, ++ "gdbarch_dump: gdbarch_get_syscall_number_p() = %d\n", ++ gdbarch_get_syscall_number_p (gdbarch)); ++ fprintf_unfiltered (file, ++ "gdbarch_dump: get_syscall_number = <%s>\n", ++ host_address_to_string (gdbarch->get_syscall_number)); ++ fprintf_unfiltered (file, + "gdbarch_dump: has_global_solist = %s\n", + plongest (gdbarch->has_global_solist)); + fprintf_unfiltered (file, +@@ -1122,6 +1161,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file) + fprintf_unfiltered (file, + "gdbarch_dump: write_pc = <%s>\n", + host_address_to_string (gdbarch->write_pc)); ++ fprintf_unfiltered (file, ++ "gdbarch_dump: xml_syscall_filename = %s\n", ++ gdbarch->xml_syscall_filename); + if (gdbarch->dump_tdep != NULL) + gdbarch->dump_tdep (gdbarch, file); + } +@@ -3333,6 +3375,119 @@ set_gdbarch_record_special_symbol (struct gdbarch *gdbarch, + } + + int ++gdbarch_get_syscall_number_p (struct gdbarch *gdbarch) ++{ ++ gdb_assert (gdbarch != NULL); ++ return gdbarch->get_syscall_number != NULL; ++} ++ ++LONGEST ++gdbarch_get_syscall_number (struct gdbarch *gdbarch, ptid_t ptid) ++{ ++ gdb_assert (gdbarch != NULL); ++ gdb_assert (gdbarch->get_syscall_number != NULL); ++ if (gdbarch_debug >= 2) ++ fprintf_unfiltered (gdb_stdlog, "gdbarch_get_syscall_number called\n"); ++ return gdbarch->get_syscall_number (gdbarch, ptid); ++} ++ ++void ++set_gdbarch_get_syscall_number (struct gdbarch *gdbarch, ++ gdbarch_get_syscall_number_ftype get_syscall_number) ++{ ++ gdbarch->get_syscall_number = get_syscall_number; ++} ++ ++int ++gdbarch_get_syscall_by_number_p (struct gdbarch *gdbarch) ++{ ++ gdb_assert (gdbarch != NULL); ++ return gdbarch->get_syscall_by_number != NULL; ++} ++ ++void ++gdbarch_get_syscall_by_number (struct gdbarch *gdbarch, int syscall_number, struct syscall *s) ++{ ++ gdb_assert (gdbarch != NULL); ++ gdb_assert (gdbarch->get_syscall_by_number != NULL); ++ if (gdbarch_debug >= 2) ++ fprintf_unfiltered (gdb_stdlog, "gdbarch_get_syscall_by_number called\n"); ++ gdbarch->get_syscall_by_number (gdbarch, syscall_number, s); ++} ++ ++void ++set_gdbarch_get_syscall_by_number (struct gdbarch *gdbarch, ++ gdbarch_get_syscall_by_number_ftype get_syscall_by_number) ++{ ++ gdbarch->get_syscall_by_number = get_syscall_by_number; ++} ++ ++int ++gdbarch_get_syscall_by_name_p (struct gdbarch *gdbarch) ++{ ++ gdb_assert (gdbarch != NULL); ++ return gdbarch->get_syscall_by_name != NULL; ++} ++ ++void ++gdbarch_get_syscall_by_name (struct gdbarch *gdbarch, const char *syscall_name, struct syscall *s) ++{ ++ gdb_assert (gdbarch != NULL); ++ gdb_assert (gdbarch->get_syscall_by_name != NULL); ++ if (gdbarch_debug >= 2) ++ fprintf_unfiltered (gdb_stdlog, "gdbarch_get_syscall_by_name called\n"); ++ gdbarch->get_syscall_by_name (gdbarch, syscall_name, s); ++} ++ ++void ++set_gdbarch_get_syscall_by_name (struct gdbarch *gdbarch, ++ gdbarch_get_syscall_by_name_ftype get_syscall_by_name) ++{ ++ gdbarch->get_syscall_by_name = get_syscall_by_name; ++} ++ ++int ++gdbarch_get_syscall_names_p (struct gdbarch *gdbarch) ++{ ++ gdb_assert (gdbarch != NULL); ++ return gdbarch->get_syscall_names != NULL; ++} ++ ++const char ** ++gdbarch_get_syscall_names (struct gdbarch *gdbarch) ++{ ++ gdb_assert (gdbarch != NULL); ++ gdb_assert (gdbarch->get_syscall_names != NULL); ++ if (gdbarch_debug >= 2) ++ fprintf_unfiltered (gdb_stdlog, "gdbarch_get_syscall_names called\n"); ++ return gdbarch->get_syscall_names (gdbarch); ++} ++ ++void ++set_gdbarch_get_syscall_names (struct gdbarch *gdbarch, ++ gdbarch_get_syscall_names_ftype get_syscall_names) ++{ ++ gdbarch->get_syscall_names = get_syscall_names; ++} ++ ++const char * ++gdbarch_xml_syscall_filename (struct gdbarch *gdbarch) ++{ ++ gdb_assert (gdbarch != NULL); ++ /* Skip verify of xml_syscall_filename, invalid_p == 0 */ ++ if (gdbarch_debug >= 2) ++ fprintf_unfiltered (gdb_stdlog, "gdbarch_xml_syscall_filename called\n"); ++ return gdbarch->xml_syscall_filename; ++} ++ ++void ++set_gdbarch_xml_syscall_filename (struct gdbarch *gdbarch, ++ const char * xml_syscall_filename) ++{ ++ gdbarch->xml_syscall_filename = xml_syscall_filename; ++} ++ ++int + gdbarch_has_global_solist (struct gdbarch *gdbarch) + { + gdb_assert (gdbarch != NULL); +diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h +index 04c8920..017b9df 100644 +--- a/gdb/gdbarch.h ++++ b/gdb/gdbarch.h +@@ -52,6 +52,7 @@ struct bp_target_info; + struct target_desc; + struct displaced_step_closure; + struct core_regset_section; ++struct syscall; + + extern struct gdbarch *current_gdbarch; + extern struct gdbarch *target_gdbarch; +@@ -839,6 +840,47 @@ typedef void (gdbarch_record_special_symbol_ftype) (struct gdbarch *gdbarch, str + extern void gdbarch_record_special_symbol (struct gdbarch *gdbarch, struct objfile *objfile, asymbol *sym); + extern void set_gdbarch_record_special_symbol (struct gdbarch *gdbarch, gdbarch_record_special_symbol_ftype *record_special_symbol); + ++/* Functions for the 'catch syscall' feature. ++ Get architecture-specific system calls information from registers. */ ++ ++extern int gdbarch_get_syscall_number_p (struct gdbarch *gdbarch); ++ ++typedef LONGEST (gdbarch_get_syscall_number_ftype) (struct gdbarch *gdbarch, ptid_t ptid); ++extern LONGEST gdbarch_get_syscall_number (struct gdbarch *gdbarch, ptid_t ptid); ++extern void set_gdbarch_get_syscall_number (struct gdbarch *gdbarch, gdbarch_get_syscall_number_ftype *get_syscall_number); ++ ++/* Fills the struct syscall (passed as argument) with the corresponding ++ system call represented by syscall_number. */ ++ ++extern int gdbarch_get_syscall_by_number_p (struct gdbarch *gdbarch); ++ ++typedef void (gdbarch_get_syscall_by_number_ftype) (struct gdbarch *gdbarch, int syscall_number, struct syscall *s); ++extern void gdbarch_get_syscall_by_number (struct gdbarch *gdbarch, int syscall_number, struct syscall *s); ++extern void set_gdbarch_get_syscall_by_number (struct gdbarch *gdbarch, gdbarch_get_syscall_by_number_ftype *get_syscall_by_number); ++ ++/* Fills the struct syscall (passed as argument) with the corresponding ++ system call represented by syscall_name. */ ++ ++extern int gdbarch_get_syscall_by_name_p (struct gdbarch *gdbarch); ++ ++typedef void (gdbarch_get_syscall_by_name_ftype) (struct gdbarch *gdbarch, const char *syscall_name, struct syscall *s); ++extern void gdbarch_get_syscall_by_name (struct gdbarch *gdbarch, const char *syscall_name, struct syscall *s); ++extern void set_gdbarch_get_syscall_by_name (struct gdbarch *gdbarch, gdbarch_get_syscall_by_name_ftype *get_syscall_by_name); ++ ++/* Returns the array containing the syscall names for the architecture. */ ++ ++extern int gdbarch_get_syscall_names_p (struct gdbarch *gdbarch); ++ ++typedef const char ** (gdbarch_get_syscall_names_ftype) (struct gdbarch *gdbarch); ++extern const char ** gdbarch_get_syscall_names (struct gdbarch *gdbarch); ++extern void set_gdbarch_get_syscall_names (struct gdbarch *gdbarch, gdbarch_get_syscall_names_ftype *get_syscall_names); ++ ++/* Stores the name of syscall's XML file. Contains NULL if the file ++ was not set. */ ++ ++extern const char * gdbarch_xml_syscall_filename (struct gdbarch *gdbarch); ++extern void set_gdbarch_xml_syscall_filename (struct gdbarch *gdbarch, const char * xml_syscall_filename); ++ + /* True if the list of shared libraries is one and only for all + processes, as opposed to a list of shared libraries per inferior. + When this property is true, GDB assumes that since shared libraries +@@ -848,6 +890,9 @@ extern void set_gdbarch_record_special_symbol (struct gdbarch *gdbarch, gdbarch_ + extern int gdbarch_has_global_solist (struct gdbarch *gdbarch); + extern void set_gdbarch_has_global_solist (struct gdbarch *gdbarch, int has_global_solist); + ++/* Definition for an unknown syscall, used basically in error-cases. */ ++#define UNKNOWN_SYSCALL (-1) ++ + extern struct gdbarch_tdep *gdbarch_tdep (struct gdbarch *gdbarch); + + +diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh +index f93bfc1..66cbcd0 100755 +--- a/gdb/gdbarch.sh ++++ b/gdb/gdbarch.sh +@@ -724,6 +724,26 @@ M:struct type *:get_siginfo_type:void: + # Record architecture-specific information from the symbol table. + M:void:record_special_symbol:struct objfile *objfile, asymbol *sym:objfile, sym + ++# Functions for the 'catch syscall' feature. ++ ++# Get architecture-specific system calls information from registers. ++M:LONGEST:get_syscall_number:ptid_t ptid:ptid ++ ++# Fills the struct syscall (passed as argument) with the corresponding ++# system call represented by syscall_number. ++M:void:get_syscall_by_number:int syscall_number, struct syscall *s:syscall_number, s ++ ++# Fills the struct syscall (passed as argument) with the corresponding ++# system call represented by syscall_name. ++M:void:get_syscall_by_name:const char *syscall_name, struct syscall *s:syscall_name, s ++ ++# Returns the array containing the syscall names for the architecture. ++M:const char **:get_syscall_names:void: ++ ++# Stores the name of syscall's XML file. Contains NULL if the file ++# was not set. ++v:const char *:xml_syscall_filename:::0:0::0:gdbarch->xml_syscall_filename ++ + # True if the list of shared libraries is one and only for all + # processes, as opposed to a list of shared libraries per inferior. + # When this property is true, GDB assumes that since shared libraries +@@ -842,6 +862,7 @@ struct bp_target_info; + struct target_desc; + struct displaced_step_closure; + struct core_regset_section; ++struct syscall; + + extern struct gdbarch *current_gdbarch; + extern struct gdbarch *target_gdbarch; +@@ -911,6 +932,9 @@ done + # close it off + cat <objfile_obstack, struct type); + TYPE_MAIN_TYPE (type) = OBSTACK_ZALLOC (&objfile->objfile_obstack, + struct main_type); + OBJSTAT (objfile, n_types++); ++ break; + } + + /* Initialize the fields that might not be zero. */ +@@ -180,6 +201,9 @@ alloc_type (struct objfile *objfile) + TYPE_VPTR_FIELDNO (type) = -1; + TYPE_CHAIN (type) = type; /* Chain back to itself. */ + ++ if (objfile == NULL) ++ type_init_refc (type, parent); ++ + return (type); + } + +@@ -194,16 +218,24 @@ alloc_type_instance (struct type *oldtype) + + /* Allocate the structure. */ + +- if (TYPE_OBJFILE (oldtype) == NULL) +- type = XZALLOC (struct type); +- else +- type = OBSTACK_ZALLOC (&TYPE_OBJFILE (oldtype)->objfile_obstack, +- struct type); +- ++ switch ((long) TYPE_OBJFILE (oldtype)) ++ { ++ case (long) OBJFILE_INTERNAL: ++ case (long) OBJFILE_MALLOC: ++ type = XZALLOC (struct type); ++ break; ++ default: ++ type = OBSTACK_ZALLOC (&TYPE_OBJFILE (oldtype)->objfile_obstack, ++ struct type); ++ break; ++ } + TYPE_MAIN_TYPE (type) = TYPE_MAIN_TYPE (oldtype); + + TYPE_CHAIN (type) = type; /* Chain back to itself for now. */ + ++ if (TYPE_OBJFILE (oldtype) == NULL) ++ type_init_refc (type, oldtype); ++ + return (type); + } + +@@ -248,7 +280,7 @@ make_pointer_type (struct type *type, struct type **typeptr) + + if (typeptr == 0 || *typeptr == 0) /* We'll need to allocate one. */ + { +- ntype = alloc_type (TYPE_OBJFILE (type)); ++ ntype = alloc_type (TYPE_OBJFILE (type), type); + if (typeptr) + *typeptr = ntype; + } +@@ -260,6 +292,9 @@ make_pointer_type (struct type *type, struct type **typeptr) + smash_type (ntype); + TYPE_CHAIN (ntype) = chain; + TYPE_OBJFILE (ntype) = objfile; ++ ++ /* Callers may only supply storage if there is an objfile. */ ++ gdb_assert (objfile); + } + + TYPE_TARGET_TYPE (ntype) = type; +@@ -328,7 +363,7 @@ make_reference_type (struct type *type, struct type **typeptr) + + if (typeptr == 0 || *typeptr == 0) /* We'll need to allocate one. */ + { +- ntype = alloc_type (TYPE_OBJFILE (type)); ++ ntype = alloc_type (TYPE_OBJFILE (type), type); + if (typeptr) + *typeptr = ntype; + } +@@ -340,6 +375,9 @@ make_reference_type (struct type *type, struct type **typeptr) + smash_type (ntype); + TYPE_CHAIN (ntype) = chain; + TYPE_OBJFILE (ntype) = objfile; ++ ++ /* Callers may only supply storage if there is an objfile. */ ++ gdb_assert (objfile); + } + + TYPE_TARGET_TYPE (ntype) = type; +@@ -388,7 +426,7 @@ make_function_type (struct type *type, struct type **typeptr) + + if (typeptr == 0 || *typeptr == 0) /* We'll need to allocate one. */ + { +- ntype = alloc_type (TYPE_OBJFILE (type)); ++ ntype = alloc_type (TYPE_OBJFILE (type), type); + if (typeptr) + *typeptr = ntype; + } +@@ -398,6 +436,9 @@ make_function_type (struct type *type, struct type **typeptr) + objfile = TYPE_OBJFILE (ntype); + smash_type (ntype); + TYPE_OBJFILE (ntype) = objfile; ++ ++ /* Callers may only supply storage if there is an objfile. */ ++ gdb_assert (objfile); + } + + TYPE_TARGET_TYPE (ntype) = type; +@@ -643,7 +684,7 @@ lookup_memberptr_type (struct type *type, struct type *domain) + { + struct type *mtype; + +- mtype = alloc_type (TYPE_OBJFILE (type)); ++ mtype = alloc_type (TYPE_OBJFILE (type), NULL); + smash_to_memberptr_type (mtype, domain, type); + return (mtype); + } +@@ -655,7 +696,7 @@ lookup_methodptr_type (struct type *to_type) + { + struct type *mtype; + +- mtype = alloc_type (TYPE_OBJFILE (to_type)); ++ mtype = alloc_type (TYPE_OBJFILE (to_type), NULL); + TYPE_TARGET_TYPE (mtype) = to_type; + TYPE_DOMAIN_TYPE (mtype) = TYPE_DOMAIN_TYPE (to_type); + TYPE_LENGTH (mtype) = cplus_method_ptr_size (to_type); +@@ -696,19 +737,20 @@ create_range_type (struct type *result_type, struct type *index_type, + int low_bound, int high_bound) + { + if (result_type == NULL) +- result_type = alloc_type (TYPE_OBJFILE (index_type)); ++ result_type = alloc_type (TYPE_OBJFILE (index_type), index_type); + TYPE_CODE (result_type) = TYPE_CODE_RANGE; + TYPE_TARGET_TYPE (result_type) = index_type; + if (TYPE_STUB (index_type)) + TYPE_TARGET_STUB (result_type) = 1; + else + TYPE_LENGTH (result_type) = TYPE_LENGTH (check_typedef (index_type)); +- TYPE_NFIELDS (result_type) = 2; ++ TYPE_NFIELDS (result_type) = 3; + TYPE_FIELDS (result_type) = TYPE_ZALLOC (result_type, + TYPE_NFIELDS (result_type) + * sizeof (struct field)); + TYPE_LOW_BOUND (result_type) = low_bound; + TYPE_HIGH_BOUND (result_type) = high_bound; ++ TYPE_BYTE_STRIDE (result_type) = 0; + + if (low_bound >= 0) + TYPE_UNSIGNED (result_type) = 1; +@@ -727,6 +769,9 @@ get_discrete_bounds (struct type *type, LONGEST *lowp, LONGEST *highp) + switch (TYPE_CODE (type)) + { + case TYPE_CODE_RANGE: ++ if (TYPE_RANGE_UPPER_BOUND_IS_UNDEFINED (type) ++ || TYPE_RANGE_LOWER_BOUND_IS_UNDEFINED (type)) ++ return -1; + *lowp = TYPE_LOW_BOUND (type); + *highp = TYPE_HIGH_BOUND (type); + return 1; +@@ -805,30 +850,56 @@ create_array_type (struct type *result_type, + + if (result_type == NULL) + { +- result_type = alloc_type (TYPE_OBJFILE (range_type)); ++ result_type = alloc_type (TYPE_OBJFILE (range_type), range_type); + } ++ else ++ { ++ /* Callers may only supply storage if there is an objfile. */ ++ gdb_assert (TYPE_OBJFILE (result_type)); ++ } ++ + TYPE_CODE (result_type) = TYPE_CODE_ARRAY; + TYPE_TARGET_TYPE (result_type) = element_type; +- if (get_discrete_bounds (range_type, &low_bound, &high_bound) < 0) +- low_bound = high_bound = 0; +- CHECK_TYPEDEF (element_type); +- /* Be careful when setting the array length. Ada arrays can be +- empty arrays with the high_bound being smaller than the low_bound. +- In such cases, the array length should be zero. */ +- if (high_bound < low_bound) +- TYPE_LENGTH (result_type) = 0; +- else +- TYPE_LENGTH (result_type) = +- TYPE_LENGTH (element_type) * (high_bound - low_bound + 1); + TYPE_NFIELDS (result_type) = 1; + TYPE_FIELDS (result_type) = + (struct field *) TYPE_ZALLOC (result_type, sizeof (struct field)); ++ /* FIXME: type alloc. */ + TYPE_INDEX_TYPE (result_type) = range_type; + TYPE_VPTR_FIELDNO (result_type) = -1; + +- /* TYPE_FLAG_TARGET_STUB will take care of zero length arrays */ ++ /* DWARF blocks may depend on runtime information like ++ DW_OP_PUSH_OBJECT_ADDRESS not being available during the ++ CREATE_ARRAY_TYPE time. */ ++ if (TYPE_RANGE_BOUND_IS_DWARF_BLOCK (range_type, 0) ++ || TYPE_RANGE_BOUND_IS_DWARF_BLOCK (range_type, 1) ++ || TYPE_RANGE_UPPER_BOUND_IS_UNDEFINED (range_type) ++ || TYPE_RANGE_LOWER_BOUND_IS_UNDEFINED (range_type) ++ || get_discrete_bounds (range_type, &low_bound, &high_bound) < 0) ++ { ++ low_bound = 0; ++ high_bound = -1; ++ } ++ ++ /* Be careful when setting the array length. Ada arrays can be ++ empty arrays with the high_bound being smaller than the low_bound. ++ In such cases, the array length should be zero. TYPE_TARGET_STUB needs to ++ be checked as it may have dependencies on DWARF blocks depending on ++ runtime information not available during the CREATE_ARRAY_TYPE time. */ ++ if (high_bound < low_bound || TYPE_TARGET_STUB (element_type)) ++ TYPE_LENGTH (result_type) = 0; ++ else ++ { ++ CHECK_TYPEDEF (element_type); ++ TYPE_LENGTH (result_type) = ++ TYPE_LENGTH (element_type) * (high_bound - low_bound + 1); ++ } ++ + if (TYPE_LENGTH (result_type) == 0) +- TYPE_TARGET_STUB (result_type) = 1; ++ { ++ /* The real size will be computed for specific instances by ++ CHECK_TYPEDEF. */ ++ TYPE_TARGET_STUB (result_type) = 1; ++ } + + return (result_type); + } +@@ -865,7 +936,12 @@ create_set_type (struct type *result_type, struct type *domain_type) + { + if (result_type == NULL) + { +- result_type = alloc_type (TYPE_OBJFILE (domain_type)); ++ result_type = alloc_type (TYPE_OBJFILE (domain_type), domain_type); ++ } ++ else ++ { ++ /* Callers may only supply storage if there is an objfile. */ ++ gdb_assert (TYPE_OBJFILE (result_type)); + } + TYPE_CODE (result_type) = TYPE_CODE_SET; + TYPE_NFIELDS (result_type) = 1; +@@ -1368,6 +1444,84 @@ stub_noname_complaint (void) + complaint (&symfile_complaints, _("stub type has NULL name")); + } + ++/* Calculate the memory length of array TYPE. ++ ++ TARGET_TYPE should be set to `check_typedef (TYPE_TARGET_TYPE (type))' as ++ a performance hint. Feel free to pass NULL. Set FULL_SPAN to return the ++ size incl. the possible padding of the last element - it may differ from the ++ cleared FULL_SPAN return value (the expected SIZEOF) for non-zero ++ TYPE_BYTE_STRIDE values. */ ++ ++static CORE_ADDR ++type_length_get (struct type *type, struct type *target_type, int full_span) ++{ ++ struct type *range_type; ++ int count; ++ CORE_ADDR byte_stride = 0; /* `= 0' for a false GCC warning. */ ++ CORE_ADDR element_size; ++ ++ if (TYPE_CODE (type) != TYPE_CODE_ARRAY ++ && TYPE_CODE (type) != TYPE_CODE_STRING) ++ return TYPE_LENGTH (type); ++ ++ /* Avoid executing TYPE_HIGH_BOUND for invalid (unallocated/unassociated) ++ Fortran arrays. The allocated data will never be used so they can be ++ zero-length. */ ++ if (object_address_data_not_valid (type)) ++ return 0; ++ ++ range_type = TYPE_INDEX_TYPE (type); ++ if (TYPE_RANGE_LOWER_BOUND_IS_UNDEFINED (range_type) ++ || TYPE_RANGE_UPPER_BOUND_IS_UNDEFINED (range_type)) ++ return 0; ++ count = TYPE_HIGH_BOUND (range_type) - TYPE_LOW_BOUND (range_type) + 1; ++ /* It may happen for wrong DWARF annotations returning garbage data. */ ++ if (count < 0) ++ warning (_("Range for type %s has invalid bounds %d..%d"), ++ TYPE_NAME (type), TYPE_LOW_BOUND (range_type), ++ TYPE_HIGH_BOUND (range_type)); ++ /* The code below does not handle count == 0 right. */ ++ if (count <= 0) ++ return 0; ++ if (full_span || count > 1) ++ { ++ /* We do not use TYPE_ARRAY_BYTE_STRIDE_VALUE (type) here as we want to ++ force FULL_SPAN to 1. */ ++ byte_stride = TYPE_BYTE_STRIDE (range_type); ++ if (byte_stride == 0) ++ { ++ if (target_type == NULL) ++ target_type = check_typedef (TYPE_TARGET_TYPE (type)); ++ byte_stride = type_length_get (target_type, NULL, 1); ++ } ++ } ++ if (full_span) ++ return count * byte_stride; ++ if (target_type == NULL) ++ target_type = check_typedef (TYPE_TARGET_TYPE (type)); ++ element_size = type_length_get (target_type, NULL, 1); ++ return (count - 1) * byte_stride + element_size; ++} ++ ++/* Prepare TYPE after being read in by the backend. Currently this function ++ only propagates the TYPE_DYNAMIC flag. */ ++ ++void ++finalize_type (struct type *type) ++{ ++ int i; ++ ++ for (i = 0; i < TYPE_NFIELDS (type); ++i) ++ if (TYPE_FIELD_TYPE (type, i) && TYPE_DYNAMIC (TYPE_FIELD_TYPE (type, i))) ++ break; ++ ++ /* FIXME: cplus_stuff is ignored here. */ ++ if (i < TYPE_NFIELDS (type) ++ || (TYPE_VPTR_BASETYPE (type) && TYPE_DYNAMIC (TYPE_VPTR_BASETYPE (type))) ++ || (TYPE_TARGET_TYPE (type) && TYPE_DYNAMIC (TYPE_TARGET_TYPE (type)))) ++ TYPE_DYNAMIC (type) = 1; ++} ++ + /* Added by Bryan Boreham, Kewill, Sun Sep 17 18:07:17 1989. + + If this is a stubbed struct (i.e. declared as struct foo *), see if +@@ -1384,7 +1538,8 @@ stub_noname_complaint (void) + /* Find the real type of TYPE. This function returns the real type, + after removing all layers of typedefs and completing opaque or stub + types. Completion changes the TYPE argument, but stripping of +- typedefs does not. */ ++ typedefs does not. Still original passed TYPE will have TYPE_LENGTH ++ updated. FIXME: Remove this dependency (only ada_to_fixed_type?). */ + + struct type * + check_typedef (struct type *type) +@@ -1420,7 +1575,7 @@ check_typedef (struct type *type) + if (sym) + TYPE_TARGET_TYPE (type) = SYMBOL_TYPE (sym); + else /* TYPE_CODE_UNDEF */ +- TYPE_TARGET_TYPE (type) = alloc_type (NULL); ++ TYPE_TARGET_TYPE (type) = alloc_type (NULL, NULL); + } + type = TYPE_TARGET_TYPE (type); + } +@@ -1494,34 +1649,37 @@ check_typedef (struct type *type) + } + } + +- if (TYPE_TARGET_STUB (type)) ++ /* copy_type_recursive automatically makes the resulting type containing only ++ constant values expected by the callers of this function. */ ++ if (TYPE_DYNAMIC (type)) ++ { ++ htab_t copied_types; ++ struct type *type_old = type; ++ ++ copied_types = create_copied_types_hash (NULL); ++ type = copy_type_recursive (type, copied_types); ++ htab_delete (copied_types); ++ ++ gdb_assert (TYPE_DYNAMIC (type) == 0); ++ } ++ ++ if (!currently_reading_symtab ++ && (TYPE_TARGET_STUB (type) || TYPE_DYNAMIC (type))) + { +- struct type *range_type; + struct type *target_type = check_typedef (TYPE_TARGET_TYPE (type)); + ++ if (TYPE_DYNAMIC (type)) ++ TYPE_TARGET_TYPE (type) = target_type; + if (TYPE_STUB (target_type) || TYPE_TARGET_STUB (target_type)) + { + /* Empty. */ + } + else if (TYPE_CODE (type) == TYPE_CODE_ARRAY +- && TYPE_NFIELDS (type) == 1 +- && (TYPE_CODE (range_type = TYPE_INDEX_TYPE (type)) +- == TYPE_CODE_RANGE)) ++ || TYPE_CODE (type) == TYPE_CODE_STRING) + { + /* Now recompute the length of the array type, based on its +- number of elements and the target type's length. +- Watch out for Ada null Ada arrays where the high bound +- is smaller than the low bound. */ +- const int low_bound = TYPE_LOW_BOUND (range_type); +- const int high_bound = TYPE_HIGH_BOUND (range_type); +- int nb_elements; +- +- if (high_bound < low_bound) +- nb_elements = 0; +- else +- nb_elements = high_bound - low_bound + 1; +- +- TYPE_LENGTH (type) = nb_elements * TYPE_LENGTH (target_type); ++ number of elements and the target type's length. */ ++ TYPE_LENGTH (type) = type_length_get (type, target_type, 0); + TYPE_TARGET_STUB (type) = 0; + } + else if (TYPE_CODE (type) == TYPE_CODE_RANGE) +@@ -1529,9 +1687,12 @@ check_typedef (struct type *type) + TYPE_LENGTH (type) = TYPE_LENGTH (target_type); + TYPE_TARGET_STUB (type) = 0; + } ++ TYPE_DYNAMIC (type) = 0; + } ++ + /* Cache TYPE_LENGTH for future use. */ + TYPE_LENGTH (orig_type) = TYPE_LENGTH (type); ++ + return type; + } + +@@ -1753,7 +1914,7 @@ init_type (enum type_code code, int length, int flags, + { + struct type *type; + +- type = alloc_type (objfile); ++ type = alloc_type (objfile, NULL); + TYPE_CODE (type) = code; + TYPE_LENGTH (type) = length; + +@@ -1783,15 +1944,24 @@ init_type (enum type_code code, int length, int flags, + if (flags & TYPE_FLAG_FIXED_INSTANCE) + TYPE_FIXED_INSTANCE (type) = 1; + +- if ((name != NULL) && (objfile != NULL)) +- { +- TYPE_NAME (type) = obsavestring (name, strlen (name), +- &objfile->objfile_obstack); +- } +- else +- { +- TYPE_NAME (type) = name; +- } ++ if (name) ++ switch ((long) objfile) ++ { ++ case (long) OBJFILE_INTERNAL: ++ TYPE_NAME (type) = name; ++ break; ++ case (long) OBJFILE_MALLOC: ++ TYPE_NAME (type) = xstrdup (name); ++ break; ++#if 0 /* OBJFILE_MALLOC duplication now. */ ++ case (long) NULL: ++ internal_error (__FILE__, __LINE__, ++ _("OBJFILE pointer NULL should be OBJFILE_* instead")); ++#endif ++ default: ++ TYPE_NAME (type) = obsavestring (name, strlen (name), ++ &objfile->objfile_obstack); ++ } + + /* C++ fancies. */ + +@@ -1803,6 +1973,10 @@ init_type (enum type_code code, int length, int flags, + { + INIT_CPLUS_SPECIFIC (type); + } ++ ++ if (!objfile) ++ type_incref (type); ++ + return (type); + } + +@@ -2916,33 +3090,47 @@ type_pair_eq (const void *item_lhs, const void *item_rhs) + } + + /* Allocate the hash table used by copy_type_recursive to walk +- types without duplicates. We use OBJFILE's obstack, because +- OBJFILE is about to be deleted. */ ++ types without duplicates. */ + + htab_t + create_copied_types_hash (struct objfile *objfile) + { +- return htab_create_alloc_ex (1, type_pair_hash, type_pair_eq, +- NULL, &objfile->objfile_obstack, +- hashtab_obstack_allocate, +- dummy_obstack_deallocate); ++ if (objfile == NULL) ++ { ++ /* NULL OBJFILE is for TYPE_DYNAMIC types already contained in ++ OBJFILE_MALLOC memory, such as those from VALUE_HISTORY_CHAIN. Table ++ element entries get allocated by xmalloc - so use xfree. */ ++ return htab_create (1, type_pair_hash, type_pair_eq, xfree); ++ } ++ else ++ { ++ /* Use OBJFILE's obstack, because OBJFILE is about to be deleted. Table ++ element entries get allocated by xmalloc - so use xfree. */ ++ return htab_create_alloc_ex (1, type_pair_hash, type_pair_eq, ++ xfree, &objfile->objfile_obstack, ++ hashtab_obstack_allocate, ++ dummy_obstack_deallocate); ++ } + } + +-/* Recursively copy (deep copy) TYPE, if it is associated with +- OBJFILE. Return a new type allocated using malloc, a saved type if +- we have already visited TYPE (using COPIED_TYPES), or TYPE if it is +- not associated with OBJFILE. */ ++/* A helper for copy_type_recursive. This does all the work. ++ REPRESENTATIVE is a pointer to a type. This is used to register ++ newly-created types in the type_refc_table. Initially it pointer ++ to a NULL pointer, but it is filled in the first time a type is ++ copied. OBJFILE is used only for an assertion checking. */ + +-struct type * +-copy_type_recursive (struct objfile *objfile, +- struct type *type, +- htab_t copied_types) ++static struct type * ++copy_type_recursive_1 (struct objfile *objfile, ++ struct type *type, ++ htab_t copied_types, ++ struct type **representative) + { + struct type_pair *stored, pair; + void **slot; + struct type *new_type; + +- if (TYPE_OBJFILE (type) == NULL) ++ if (TYPE_OBJFILE (type) == OBJFILE_INTERNAL ++ || (objfile == OBJFILE_MALLOC && !TYPE_DYNAMIC (type))) + return type; + + /* This type shouldn't be pointing to any types in other objfiles; +@@ -2954,11 +3142,15 @@ copy_type_recursive (struct objfile *objfile, + if (*slot != NULL) + return ((struct type_pair *) *slot)->new; + +- new_type = alloc_type (NULL); ++ new_type = alloc_type (OBJFILE_MALLOC, *representative); ++ if (!*representative) ++ *representative = new_type; + + /* We must add the new type to the hash table immediately, in case +- we encounter this type again during a recursive call below. */ +- stored = obstack_alloc (&objfile->objfile_obstack, sizeof (struct type_pair)); ++ we encounter this type again during a recursive call below. Memory could ++ be allocated from OBJFILE in the case we will be removing OBJFILE, this ++ optimization is missed and xfree is called for it from COPIED_TYPES. */ ++ stored = xmalloc (sizeof (*stored)); + stored->old = type; + stored->new = new_type; + *slot = stored; +@@ -2968,6 +3160,13 @@ copy_type_recursive (struct objfile *objfile, + *TYPE_MAIN_TYPE (new_type) = *TYPE_MAIN_TYPE (type); + TYPE_OBJFILE (new_type) = NULL; + ++ /* Pre-clear the fields processed by delete_main_type. If DWARF block ++ evaluations below call error we would leave an unfreeable TYPE. */ ++ TYPE_TARGET_TYPE (new_type) = NULL; ++ TYPE_VPTR_BASETYPE (new_type) = NULL; ++ TYPE_NFIELDS (new_type) = 0; ++ TYPE_FIELDS (new_type) = NULL; ++ + if (TYPE_NAME (type)) + TYPE_NAME (new_type) = xstrdup (TYPE_NAME (type)); + if (TYPE_TAG_NAME (type)) +@@ -2976,12 +3175,45 @@ copy_type_recursive (struct objfile *objfile, + TYPE_INSTANCE_FLAGS (new_type) = TYPE_INSTANCE_FLAGS (type); + TYPE_LENGTH (new_type) = TYPE_LENGTH (type); + ++ if (TYPE_ALLOCATED (new_type)) ++ { ++ gdb_assert (!TYPE_NOT_ALLOCATED (new_type)); ++ ++ if (!dwarf_locexpr_baton_eval (TYPE_ALLOCATED (new_type))) ++ TYPE_NOT_ALLOCATED (new_type) = 1; ++ TYPE_ALLOCATED (new_type) = NULL; ++ } ++ ++ if (TYPE_ASSOCIATED (new_type)) ++ { ++ gdb_assert (!TYPE_NOT_ASSOCIATED (new_type)); ++ ++ if (!dwarf_locexpr_baton_eval (TYPE_ASSOCIATED (new_type))) ++ TYPE_NOT_ASSOCIATED (new_type) = 1; ++ TYPE_ASSOCIATED (new_type) = NULL; ++ } ++ ++ if (!TYPE_DATA_LOCATION_IS_ADDR (new_type) ++ && TYPE_DATA_LOCATION_DWARF_BLOCK (new_type)) ++ { ++ if (TYPE_NOT_ALLOCATED (new_type) ++ || TYPE_NOT_ASSOCIATED (new_type)) ++ TYPE_DATA_LOCATION_DWARF_BLOCK (new_type) = NULL; ++ else ++ { ++ TYPE_DATA_LOCATION_IS_ADDR (new_type) = 1; ++ TYPE_DATA_LOCATION_ADDR (new_type) = dwarf_locexpr_baton_eval ++ (TYPE_DATA_LOCATION_DWARF_BLOCK (new_type)); ++ } ++ } ++ + /* Copy the fields. */ + if (TYPE_NFIELDS (type)) + { + int i, nfields; + + nfields = TYPE_NFIELDS (type); ++ TYPE_NFIELDS (new_type) = nfields; + TYPE_FIELDS (new_type) = XCALLOC (nfields, struct field); + for (i = 0; i < nfields; i++) + { +@@ -2990,8 +3222,8 @@ copy_type_recursive (struct objfile *objfile, + TYPE_FIELD_BITSIZE (new_type, i) = TYPE_FIELD_BITSIZE (type, i); + if (TYPE_FIELD_TYPE (type, i)) + TYPE_FIELD_TYPE (new_type, i) +- = copy_type_recursive (objfile, TYPE_FIELD_TYPE (type, i), +- copied_types); ++ = copy_type_recursive_1 (objfile, TYPE_FIELD_TYPE (type, i), ++ copied_types, representative); + if (TYPE_FIELD_NAME (type, i)) + TYPE_FIELD_NAME (new_type, i) = + xstrdup (TYPE_FIELD_NAME (type, i)); +@@ -3010,6 +3242,16 @@ copy_type_recursive (struct objfile *objfile, + xstrdup (TYPE_FIELD_STATIC_PHYSNAME (type, + i))); + break; ++ case FIELD_LOC_KIND_DWARF_BLOCK: ++ /* `struct dwarf2_locexpr_baton' is too bound to its objfile so ++ it is expected to be made constant by CHECK_TYPEDEF. */ ++ if (TYPE_NOT_ALLOCATED (new_type) ++ || TYPE_NOT_ASSOCIATED (new_type)) ++ SET_FIELD_DWARF_BLOCK (TYPE_FIELD (new_type, i), NULL); ++ else ++ SET_FIELD_BITPOS (TYPE_FIELD (new_type, i), ++ dwarf_locexpr_baton_eval (TYPE_FIELD_DWARF_BLOCK (type, i))); ++ break; + default: + internal_error (__FILE__, __LINE__, + _("Unexpected type field location kind: %d"), +@@ -3018,17 +3260,32 @@ copy_type_recursive (struct objfile *objfile, + } + } + ++ /* Convert TYPE_RANGE_HIGH_BOUND_IS_COUNT into a regular bound. */ ++ if (TYPE_CODE (type) == TYPE_CODE_RANGE ++ && TYPE_RANGE_HIGH_BOUND_IS_COUNT (type)) ++ { ++ TYPE_RANGE_HIGH_BOUND_IS_COUNT (new_type) = 0; ++ TYPE_HIGH_BOUND (new_type) = TYPE_LOW_BOUND (type) ++ + TYPE_HIGH_BOUND (type) - 1; ++ } ++ ++ /* Both FIELD_LOC_KIND_DWARF_BLOCK and TYPE_RANGE_HIGH_BOUND_IS_COUNT were ++ possibly converted. */ ++ TYPE_DYNAMIC (new_type) = 0; ++ + /* Copy pointers to other types. */ + if (TYPE_TARGET_TYPE (type)) + TYPE_TARGET_TYPE (new_type) = +- copy_type_recursive (objfile, +- TYPE_TARGET_TYPE (type), +- copied_types); ++ copy_type_recursive_1 (objfile, ++ TYPE_TARGET_TYPE (type), ++ copied_types, ++ representative); + if (TYPE_VPTR_BASETYPE (type)) + TYPE_VPTR_BASETYPE (new_type) = +- copy_type_recursive (objfile, +- TYPE_VPTR_BASETYPE (type), +- copied_types); ++ copy_type_recursive_1 (objfile, ++ TYPE_VPTR_BASETYPE (type), ++ copied_types, ++ representative); + /* Maybe copy the type_specific bits. + + NOTE drow/2005-12-09: We do not copy the C++-specific bits like +@@ -3046,6 +3303,20 @@ copy_type_recursive (struct objfile *objfile, + return new_type; + } + ++/* Recursively copy (deep copy) TYPE. Return a new type allocated using ++ malloc, a saved type if we have already visited TYPE (using COPIED_TYPES), ++ or TYPE if it is not associated with OBJFILE. */ ++ ++struct type * ++copy_type_recursive (struct type *type, ++ htab_t copied_types) ++{ ++ struct type *representative = NULL; ++ ++ return copy_type_recursive_1 (TYPE_OBJFILE (type), type, copied_types, ++ &representative); ++} ++ + /* Make a copy of the given TYPE, except that the pointer & reference + types are not preserved. + +@@ -3059,7 +3330,7 @@ copy_type (const struct type *type) + + gdb_assert (TYPE_OBJFILE (type) != NULL); + +- new_type = alloc_type (TYPE_OBJFILE (type)); ++ new_type = alloc_type (TYPE_OBJFILE (type), NULL); + TYPE_INSTANCE_FLAGS (new_type) = TYPE_INSTANCE_FLAGS (type); + TYPE_LENGTH (new_type) = TYPE_LENGTH (type); + memcpy (TYPE_MAIN_TYPE (new_type), TYPE_MAIN_TYPE (type), +@@ -3068,6 +3339,232 @@ copy_type (const struct type *type) + return new_type; + } + ++static void delete_type (struct type *type); ++ ++/* A helper for delete_type which deletes a main_type and the things to which ++ it refers. TYPE is a type whose main_type we wish to destroy. */ ++ ++static void ++delete_main_type (struct main_type *main_type) ++{ ++ int i; ++ void **slot; ++ struct ++ { ++ struct main_type *main_type; ++ } type_local = { main_type }, *type = &type_local; ++ ++ gdb_assert (TYPE_OBJFILE (type) == OBJFILE_MALLOC); ++ ++ xfree (TYPE_NAME (type)); ++ xfree (TYPE_TAG_NAME (type)); ++ ++ for (i = 0; i < TYPE_NFIELDS (type); ++i) ++ { ++ xfree (TYPE_FIELD_NAME (type, i)); ++ ++ if (TYPE_FIELD_LOC_KIND (type, i) == FIELD_LOC_KIND_PHYSNAME) ++ xfree (TYPE_FIELD_STATIC_PHYSNAME (type, i)); ++ } ++ xfree (TYPE_FIELDS (type)); ++ ++ /* Strangely, HAVE_CPLUS_STRUCT will return true when there isn't ++ one at all. */ ++ gdb_assert (!HAVE_CPLUS_STRUCT (type) || !TYPE_CPLUS_SPECIFIC (type)); ++ ++ xfree (TYPE_MAIN_TYPE (type)); ++} ++ ++/* Store `struct main_type *' entries which got `struct type *' deleted. */ ++ ++static htab_t deleted_main_types_hash; ++ ++/* To be called before any call of delete_type. */ ++ ++static void ++delete_type_begin (void) ++{ ++ gdb_assert (deleted_main_types_hash == NULL); ++ ++ deleted_main_types_hash = htab_create_alloc (10, htab_hash_pointer, ++ htab_eq_pointer, NULL, xcalloc, xfree); ++} ++ ++/* Helper for delete_type_finish. */ ++ ++static int ++delete_type_finish_traverse (void **slot, void *unused) ++{ ++ struct main_type *main_type = *slot; ++ ++ delete_main_type (main_type); ++ ++ return 1; ++} ++ ++/* To be called after all the calls of delete_type. Each MAIN_TYPE must have ++ either none or all of its TYPE entries deleted. */ ++ ++static void ++delete_type_finish (void) ++{ ++ htab_traverse (deleted_main_types_hash, delete_type_finish_traverse, NULL); ++ ++ htab_delete (deleted_main_types_hash); ++ deleted_main_types_hash = NULL; ++} ++ ++/* Delete TYPE and remember MAIN_TYPE it references. TYPE must have been ++ allocated using xmalloc -- not using an objfile. You must wrap calls of ++ this function by delete_type_begin and delete_type_finish. */ ++ ++static void ++delete_type (struct type *type) ++{ ++ void **slot; ++ ++ if (!type) ++ return; ++ ++ if (TYPE_OBJFILE (type) == OBJFILE_INTERNAL) ++ return; ++ gdb_assert (TYPE_OBJFILE (type) == OBJFILE_MALLOC); ++ ++ slot = htab_find_slot (deleted_main_types_hash, TYPE_MAIN_TYPE (type), ++ INSERT); ++ gdb_assert (!*slot); ++ *slot = TYPE_MAIN_TYPE (type); ++ ++ xfree (type); ++} ++ ++/* Hash function for type_refc_table. */ ++ ++static hashval_t ++type_refc_hash (const void *p) ++{ ++ const struct type_refc_entry *entry = p; ++ return htab_hash_pointer (entry->type); ++} ++ ++/* Equality function for type_refc_table. */ ++ ++static int ++type_refc_equal (const void *a, const void *b) ++{ ++ const struct type_refc_entry *left = a; ++ const struct type_refc_entry *right = b; ++ return left->type == right->type; ++} ++ ++/* Insert the new type NEW_TYPE into the table. Does nothing if ++ NEW_TYPE has an objfile. If PARENT_TYPE is not NULL, then NEW_TYPE ++ will be inserted into the same hierarchy as PARENT_TYPE. In this ++ case, PARENT_TYPE must already exist in the reference count map. ++ If PARENT_TYPE is NULL, a new reference count is allocated and set ++ to one. */ ++ ++static void ++type_init_refc (struct type *new_type, struct type *parent_type) ++{ ++ int *refc; ++ void **slot; ++ struct type_refc_entry *new_entry; ++ ++ if (TYPE_OBJFILE (new_type)) ++ return; ++ ++ if (parent_type) ++ { ++ struct type_refc_entry entry, *found; ++ entry.type = parent_type; ++ found = htab_find (type_refc_table, &entry); ++ gdb_assert (found); ++ refc = found->refc; ++ } ++ else ++ { ++ refc = xmalloc (sizeof (int)); ++ *refc = 0; ++ } ++ ++ new_entry = XNEW (struct type_refc_entry); ++ new_entry->type = new_type; ++ new_entry->refc = refc; ++ ++ slot = htab_find_slot (type_refc_table, new_entry, INSERT); ++ gdb_assert (!*slot); ++ *slot = new_entry; ++} ++ ++/* Increment the reference count for TYPE. */ ++ ++void ++type_incref (struct type *type) ++{ ++ struct type_refc_entry entry, *found; ++ ++ if (TYPE_OBJFILE (type)) ++ return; ++ ++ entry.type = type; ++ found = htab_find (type_refc_table, &entry); ++ gdb_assert (found); ++ ++*(found->refc); ++} ++ ++/* A traverse callback for type_refc_table which removes any entry ++ whose reference count is zero (unused entry). */ ++ ++static int ++type_refc_remove (void **slot, void *unused) ++{ ++ struct type_refc_entry *entry = *slot; ++ ++ if (*entry->refc == 0) ++ { ++ delete_type (entry->type); ++ ++ xfree (entry); ++ htab_clear_slot (type_refc_table, slot); ++ } ++ ++ return 1; ++} ++ ++/* Decrement the reference count for TYPE. Even if TYPE has no more ++ references still do not delete it as callers may hold pointers to types ++ dynamically generated by check_typedef where type_incref is never called. ++ Always rely on the free_all_types garbage collector. */ ++ ++void ++type_decref (struct type *type) ++{ ++ struct type_refc_entry entry, *found; ++ ++ if (TYPE_OBJFILE (type)) ++ return; ++ ++ entry.type = type; ++ found = htab_find (type_refc_table, &entry); ++ gdb_assert (found); ++ gdb_assert (found->refc > 0); ++ --*(found->refc); ++} ++ ++/* Free all the types that have been allocated and that are not used according ++ to type_refc_entry->refc. Called after each command, successful or not. ++ Use this cleanup only in the GDB idle state as GDB code does not necessarily ++ use type_incref / type_decref during temporary use of types. */ ++ ++void ++free_all_types (void) ++{ ++ delete_type_begin (); ++ htab_traverse (type_refc_table, type_refc_remove, NULL); ++ delete_type_finish (); ++} ++ + static struct type * + build_flt (int bit, char *name, const struct floatformat **floatformats) + { +@@ -3105,7 +3602,7 @@ build_complex (int bit, char *name, struct type *target_type) + return builtin_type_error; + } + t = init_type (TYPE_CODE_COMPLEX, 2 * bit / TARGET_CHAR_BIT, +- 0, name, (struct objfile *) NULL); ++ 0, name, OBJFILE_INTERNAL); + TYPE_TARGET_TYPE (t) = target_type; + return t; + } +@@ -3119,56 +3616,56 @@ gdbtypes_post_init (struct gdbarch *gdbarch) + builtin_type->builtin_void = + init_type (TYPE_CODE_VOID, 1, + 0, +- "void", (struct objfile *) NULL); ++ "void", OBJFILE_INTERNAL); + builtin_type->builtin_char = + init_type (TYPE_CODE_INT, TARGET_CHAR_BIT / TARGET_CHAR_BIT, + (TYPE_FLAG_NOSIGN + | (gdbarch_char_signed (gdbarch) ? 0 : TYPE_FLAG_UNSIGNED)), +- "char", (struct objfile *) NULL); ++ "char", OBJFILE_INTERNAL); + builtin_type->builtin_signed_char = + init_type (TYPE_CODE_INT, TARGET_CHAR_BIT / TARGET_CHAR_BIT, + 0, +- "signed char", (struct objfile *) NULL); ++ "signed char", OBJFILE_INTERNAL); + builtin_type->builtin_unsigned_char = + init_type (TYPE_CODE_INT, TARGET_CHAR_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, +- "unsigned char", (struct objfile *) NULL); ++ "unsigned char", OBJFILE_INTERNAL); + builtin_type->builtin_short = + init_type (TYPE_CODE_INT, + gdbarch_short_bit (gdbarch) / TARGET_CHAR_BIT, +- 0, "short", (struct objfile *) NULL); ++ 0, "short", OBJFILE_INTERNAL); + builtin_type->builtin_unsigned_short = + init_type (TYPE_CODE_INT, + gdbarch_short_bit (gdbarch) / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, "unsigned short", +- (struct objfile *) NULL); ++ OBJFILE_INTERNAL); + builtin_type->builtin_int = + init_type (TYPE_CODE_INT, + gdbarch_int_bit (gdbarch) / TARGET_CHAR_BIT, +- 0, "int", (struct objfile *) NULL); ++ 0, "int", OBJFILE_INTERNAL); + builtin_type->builtin_unsigned_int = + init_type (TYPE_CODE_INT, + gdbarch_int_bit (gdbarch) / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, "unsigned int", +- (struct objfile *) NULL); ++ OBJFILE_INTERNAL); + builtin_type->builtin_long = + init_type (TYPE_CODE_INT, + gdbarch_long_bit (gdbarch) / TARGET_CHAR_BIT, +- 0, "long", (struct objfile *) NULL); ++ 0, "long", OBJFILE_INTERNAL); + builtin_type->builtin_unsigned_long = + init_type (TYPE_CODE_INT, + gdbarch_long_bit (gdbarch) / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, "unsigned long", +- (struct objfile *) NULL); ++ OBJFILE_INTERNAL); + builtin_type->builtin_long_long = + init_type (TYPE_CODE_INT, + gdbarch_long_long_bit (gdbarch) / TARGET_CHAR_BIT, +- 0, "long long", (struct objfile *) NULL); ++ 0, "long long", OBJFILE_INTERNAL); + builtin_type->builtin_unsigned_long_long = + init_type (TYPE_CODE_INT, + gdbarch_long_long_bit (gdbarch) / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, "unsigned long long", +- (struct objfile *) NULL); ++ OBJFILE_INTERNAL); + builtin_type->builtin_float + = build_flt (gdbarch_float_bit (gdbarch), "float", + gdbarch_float_format (gdbarch)); +@@ -3187,26 +3684,26 @@ gdbtypes_post_init (struct gdbarch *gdbarch) + builtin_type->builtin_string = + init_type (TYPE_CODE_STRING, TARGET_CHAR_BIT / TARGET_CHAR_BIT, + 0, +- "string", (struct objfile *) NULL); ++ "string", OBJFILE_INTERNAL); + builtin_type->builtin_bool = + init_type (TYPE_CODE_BOOL, TARGET_CHAR_BIT / TARGET_CHAR_BIT, + 0, +- "bool", (struct objfile *) NULL); ++ "bool", OBJFILE_INTERNAL); + + /* The following three are about decimal floating point types, which + are 32-bits, 64-bits and 128-bits respectively. */ + builtin_type->builtin_decfloat + = init_type (TYPE_CODE_DECFLOAT, 32 / 8, + 0, +- "_Decimal32", (struct objfile *) NULL); ++ "_Decimal32", OBJFILE_INTERNAL); + builtin_type->builtin_decdouble + = init_type (TYPE_CODE_DECFLOAT, 64 / 8, + 0, +- "_Decimal64", (struct objfile *) NULL); ++ "_Decimal64", OBJFILE_INTERNAL); + builtin_type->builtin_declong + = init_type (TYPE_CODE_DECFLOAT, 128 / 8, + 0, +- "_Decimal128", (struct objfile *) NULL); ++ "_Decimal128", OBJFILE_INTERNAL); + + /* Pointer/Address types. */ + +@@ -3245,27 +3742,28 @@ gdbtypes_post_init (struct gdbarch *gdbarch) + init_type (TYPE_CODE_INT, + gdbarch_addr_bit (gdbarch) / 8, + TYPE_FLAG_UNSIGNED, +- "__CORE_ADDR", (struct objfile *) NULL); ++ "__CORE_ADDR", OBJFILE_INTERNAL); + + + /* The following set of types is used for symbols with no + debug information. */ + builtin_type->nodebug_text_symbol = + init_type (TYPE_CODE_FUNC, 1, 0, +- "", NULL); ++ "", OBJFILE_INTERNAL); + TYPE_TARGET_TYPE (builtin_type->nodebug_text_symbol) = + builtin_type->builtin_int; + builtin_type->nodebug_data_symbol = + init_type (TYPE_CODE_INT, + gdbarch_int_bit (gdbarch) / HOST_CHAR_BIT, 0, +- "", NULL); ++ "", OBJFILE_INTERNAL); + builtin_type->nodebug_unknown_symbol = + init_type (TYPE_CODE_INT, 1, 0, +- "", NULL); ++ "", ++ OBJFILE_INTERNAL); + builtin_type->nodebug_tls_symbol = + init_type (TYPE_CODE_INT, + gdbarch_int_bit (gdbarch) / HOST_CHAR_BIT, 0, +- "", NULL); ++ "", OBJFILE_INTERNAL); + + return builtin_type; + } +@@ -3276,6 +3774,9 @@ _initialize_gdbtypes (void) + { + gdbtypes_data = gdbarch_data_register_post_init (gdbtypes_post_init); + ++ type_refc_table = htab_create_alloc (20, type_refc_hash, type_refc_equal, ++ NULL, xcalloc, xfree); ++ + /* FIXME: The following types are architecture-neutral. However, + they contain pointer_type and reference_type fields potentially + caching pointer or reference types that *are* architecture +@@ -3284,47 +3785,47 @@ _initialize_gdbtypes (void) + builtin_type_int0 = + init_type (TYPE_CODE_INT, 0 / 8, + 0, +- "int0_t", (struct objfile *) NULL); ++ "int0_t", OBJFILE_INTERNAL); + builtin_type_int8 = + init_type (TYPE_CODE_INT, 8 / 8, + TYPE_FLAG_NOTTEXT, +- "int8_t", (struct objfile *) NULL); ++ "int8_t", OBJFILE_INTERNAL); + builtin_type_uint8 = + init_type (TYPE_CODE_INT, 8 / 8, + TYPE_FLAG_UNSIGNED | TYPE_FLAG_NOTTEXT, +- "uint8_t", (struct objfile *) NULL); ++ "uint8_t", OBJFILE_INTERNAL); + builtin_type_int16 = + init_type (TYPE_CODE_INT, 16 / 8, + 0, +- "int16_t", (struct objfile *) NULL); ++ "int16_t", OBJFILE_INTERNAL); + builtin_type_uint16 = + init_type (TYPE_CODE_INT, 16 / 8, + TYPE_FLAG_UNSIGNED, +- "uint16_t", (struct objfile *) NULL); ++ "uint16_t", OBJFILE_INTERNAL); + builtin_type_int32 = + init_type (TYPE_CODE_INT, 32 / 8, + 0, +- "int32_t", (struct objfile *) NULL); ++ "int32_t", OBJFILE_INTERNAL); + builtin_type_uint32 = + init_type (TYPE_CODE_INT, 32 / 8, + TYPE_FLAG_UNSIGNED, +- "uint32_t", (struct objfile *) NULL); ++ "uint32_t", OBJFILE_INTERNAL); + builtin_type_int64 = + init_type (TYPE_CODE_INT, 64 / 8, + 0, +- "int64_t", (struct objfile *) NULL); ++ "int64_t", OBJFILE_INTERNAL); + builtin_type_uint64 = + init_type (TYPE_CODE_INT, 64 / 8, + TYPE_FLAG_UNSIGNED, +- "uint64_t", (struct objfile *) NULL); ++ "uint64_t", OBJFILE_INTERNAL); + builtin_type_int128 = + init_type (TYPE_CODE_INT, 128 / 8, + 0, +- "int128_t", (struct objfile *) NULL); ++ "int128_t", OBJFILE_INTERNAL); + builtin_type_uint128 = + init_type (TYPE_CODE_INT, 128 / 8, + TYPE_FLAG_UNSIGNED, +- "uint128_t", (struct objfile *) NULL); ++ "uint128_t", OBJFILE_INTERNAL); + + builtin_type_ieee_single = + build_flt (-1, "builtin_type_ieee_single", floatformats_ieee_single); +@@ -3344,15 +3845,15 @@ _initialize_gdbtypes (void) + builtin_type_void = + init_type (TYPE_CODE_VOID, 1, + 0, +- "void", (struct objfile *) NULL); ++ "void", OBJFILE_INTERNAL); + builtin_type_true_char = + init_type (TYPE_CODE_CHAR, TARGET_CHAR_BIT / TARGET_CHAR_BIT, + 0, +- "true character", (struct objfile *) NULL); ++ "true character", OBJFILE_INTERNAL); + builtin_type_true_unsigned_char = + init_type (TYPE_CODE_CHAR, TARGET_CHAR_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, +- "true character", (struct objfile *) NULL); ++ "true character", OBJFILE_INTERNAL); + + add_setshow_zinteger_cmd ("overload", no_class, &overload_debug, _("\ + Set debugging of C++ overloading."), _("\ +diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h +index c90b6d7..077b89c 100644 +--- a/gdb/gdbtypes.h ++++ b/gdb/gdbtypes.h +@@ -134,7 +134,10 @@ enum type_code + + TYPE_CODE_NAMESPACE, /* C++ namespace. */ + +- TYPE_CODE_DECFLOAT /* Decimal floating point. */ ++ TYPE_CODE_DECFLOAT, /* Decimal floating point. */ ++ ++ /* Internal function type. */ ++ TYPE_CODE_INTERNAL_FUNCTION + }; + + /* For now allow source to use TYPE_CODE_CLASS for C++ classes, as an +@@ -209,6 +212,11 @@ enum type_instance_flag_value + + #define TYPE_TARGET_STUB(t) (TYPE_MAIN_TYPE (t)->flag_target_stub) + ++/* Type needs to be evaluated on each CHECK_TYPEDEF and its results must not be ++ sticky. */ ++ ++#define TYPE_DYNAMIC(t) (TYPE_MAIN_TYPE (t)->flag_dynamic) ++ + /* Static type. If this is set, the corresponding type had + * a static modifier. + * Note: This may be unnecessary, since static data members +@@ -266,6 +274,36 @@ enum type_instance_flag_value + + #define TYPE_NOTTEXT(t) (TYPE_MAIN_TYPE (t)->flag_nottext) + ++/* Is HIGH_BOUND a low-bound relative count (1) or the high bound itself (0)? */ ++ ++#define TYPE_RANGE_HIGH_BOUND_IS_COUNT(range_type) \ ++ (TYPE_MAIN_TYPE (range_type)->flag_range_high_bound_is_count) ++ ++/* Not allocated. TYPE_ALLOCATED(t) must be NULL in such case. If this flag ++ is unset and TYPE_ALLOCATED(t) is NULL then the type is allocated. If this ++ flag is unset and TYPE_ALLOCATED(t) is not NULL then its DWARF block ++ determines the actual allocation state. */ ++ ++#define TYPE_NOT_ALLOCATED(t) (TYPE_MAIN_TYPE (t)->flag_not_allocated) ++ ++/* Not associated. TYPE_ASSOCIATED(t) must be NULL in such case. If this flag ++ is unset and TYPE_ASSOCIATED(t) is NULL then the type is associated. If ++ this flag is unset and TYPE_ASSOCIATED(t) is not NULL then its DWARF block ++ determines the actual association state. */ ++ ++#define TYPE_NOT_ASSOCIATED(t) (TYPE_MAIN_TYPE (t)->flag_not_associated) ++ ++/* Address of the actual data as for DW_AT_data_location. Its dwarf block must ++ not be evaluated unless both TYPE_NOT_ALLOCATED and TYPE_NOT_ASSOCIATED are ++ false. If TYPE_DATA_LOCATION_IS_ADDR set then TYPE_DATA_LOCATION_ADDR value ++ is the actual data address value. If unset and ++ TYPE_DATA_LOCATION_DWARF_BLOCK is NULL then the value is the normal ++ VALUE_ADDRESS copy. If unset and TYPE_DATA_LOCATION_DWARF_BLOCK is not NULL ++ then its DWARF block determines the actual data address. */ ++ ++#define TYPE_DATA_LOCATION_IS_ADDR(t) \ ++ (TYPE_MAIN_TYPE (t)->flag_data_location_is_addr) ++ + /* Constant type. If this is set, the corresponding type has a + * const modifier. + */ +@@ -352,6 +390,11 @@ struct main_type + unsigned int flag_stub_supported : 1; + unsigned int flag_nottext : 1; + unsigned int flag_fixed_instance : 1; ++ unsigned int flag_dynamic : 1; ++ unsigned int flag_range_high_bound_is_count : 1; ++ unsigned int flag_not_allocated : 1; ++ unsigned int flag_not_associated : 1; ++ unsigned int flag_data_location_is_addr : 1; + + /* Number of fields described for this type. This field appears at + this location because it packs nicely here. */ +@@ -414,6 +457,20 @@ struct main_type + + struct type *target_type; + ++ /* For DW_AT_data_location. */ ++ union ++ { ++ struct dwarf2_locexpr_baton *dwarf_block; ++ CORE_ADDR addr; ++ } ++ data_location; ++ ++ /* For DW_AT_allocated. */ ++ struct dwarf2_locexpr_baton *allocated; ++ ++ /* For DW_AT_associated. */ ++ struct dwarf2_locexpr_baton *associated; ++ + /* For structure and union types, a description of each field. + For set and pascal array types, there is one "field", + whose type is the domain type of the set or array. +@@ -795,9 +852,9 @@ extern void allocate_cplus_struct_type (struct type *); + #define TYPE_POINTER_TYPE(thistype) (thistype)->pointer_type + #define TYPE_REFERENCE_TYPE(thistype) (thistype)->reference_type + #define TYPE_CHAIN(thistype) (thistype)->chain +-/* Note that if thistype is a TYPEDEF type, you have to call check_typedef. +- But check_typedef does set the TYPE_LENGTH of the TYPEDEF type, +- so you only have to call check_typedef once. Since allocate_value ++/* Note that if thistype is a TYPEDEF, ARRAY or STRING type, you have to call ++ check_typedef. But check_typedef does set the TYPE_LENGTH of the TYPEDEF ++ type, so you only have to call check_typedef once. Since allocate_value + calls check_typedef, TYPE_LENGTH (VALUE_TYPE (X)) is safe. */ + #define TYPE_LENGTH(thistype) (thistype)->length + #define TYPE_OBJFILE(thistype) TYPE_MAIN_TYPE(thistype)->objfile +@@ -807,23 +864,44 @@ extern void allocate_cplus_struct_type (struct type *); + #define TYPE_NFIELDS(thistype) TYPE_MAIN_TYPE(thistype)->nfields + #define TYPE_FIELDS(thistype) TYPE_MAIN_TYPE(thistype)->fields + #define TYPE_TEMPLATE_ARGS(thistype) TYPE_CPLUS_SPECIFIC(thistype)->template_args ++#define TYPE_DATA_LOCATION_DWARF_BLOCK(thistype) TYPE_MAIN_TYPE (thistype)->data_location.dwarf_block ++#define TYPE_DATA_LOCATION_ADDR(thistype) TYPE_MAIN_TYPE (thistype)->data_location.addr ++#define TYPE_ALLOCATED(thistype) TYPE_MAIN_TYPE (thistype)->allocated ++#define TYPE_ASSOCIATED(thistype) TYPE_MAIN_TYPE (thistype)->associated + + #define TYPE_INDEX_TYPE(type) TYPE_FIELD_TYPE (type, 0) + #define TYPE_LOW_BOUND(range_type) TYPE_FIELD_BITPOS (range_type, 0) + #define TYPE_HIGH_BOUND(range_type) TYPE_FIELD_BITPOS (range_type, 1) +- +-/* Moto-specific stuff for FORTRAN arrays */ +- +-#define TYPE_ARRAY_UPPER_BOUND_IS_UNDEFINED(arraytype) \ +- (TYPE_FIELD_ARTIFICIAL(TYPE_INDEX_TYPE((arraytype)),1)) ++#define TYPE_BYTE_STRIDE(range_type) TYPE_FIELD_BITPOS (range_type, 2) ++ ++/* Whether we should use TYPE_FIELD_DWARF_BLOCK (and not TYPE_FIELD_BITPOS). */ ++#define TYPE_RANGE_BOUND_IS_DWARF_BLOCK(range_type, fieldno) \ ++ (TYPE_FIELD_LOC_KIND (range_type, fieldno) == FIELD_LOC_KIND_DWARF_BLOCK) ++#define TYPE_RANGE_BOUND_SET_DWARF_BLOCK(range_type, fieldno) \ ++ (TYPE_FIELD_LOC_KIND (range_type, fieldno) = FIELD_LOC_KIND_DWARF_BLOCK) ++#define TYPE_ARRAY_BOUND_IS_DWARF_BLOCK(array_type, fieldno) \ ++ TYPE_RANGE_BOUND_IS_DWARF_BLOCK (TYPE_INDEX_TYPE (array_type), fieldno) ++ ++/* Unbound arrays, such as GCC array[]; at end of struct. */ ++#define TYPE_RANGE_LOWER_BOUND_IS_UNDEFINED(rangetype) \ ++ TYPE_FIELD_ARTIFICIAL((rangetype),0) ++#define TYPE_RANGE_UPPER_BOUND_IS_UNDEFINED(rangetype) \ ++ TYPE_FIELD_ARTIFICIAL((rangetype),1) + #define TYPE_ARRAY_LOWER_BOUND_IS_UNDEFINED(arraytype) \ +- (TYPE_FIELD_ARTIFICIAL(TYPE_INDEX_TYPE((arraytype)),0)) +- +-#define TYPE_ARRAY_UPPER_BOUND_VALUE(arraytype) \ +- (TYPE_HIGH_BOUND(TYPE_INDEX_TYPE((arraytype)))) ++ TYPE_RANGE_LOWER_BOUND_IS_UNDEFINED (TYPE_INDEX_TYPE (arraytype)) ++#define TYPE_ARRAY_UPPER_BOUND_IS_UNDEFINED(arraytype) \ ++ TYPE_RANGE_UPPER_BOUND_IS_UNDEFINED (TYPE_INDEX_TYPE (arraytype)) + + #define TYPE_ARRAY_LOWER_BOUND_VALUE(arraytype) \ +- (TYPE_LOW_BOUND(TYPE_INDEX_TYPE((arraytype)))) ++ TYPE_LOW_BOUND (TYPE_INDEX_TYPE (arraytype)) ++#define TYPE_ARRAY_UPPER_BOUND_VALUE(arraytype) \ ++ TYPE_HIGH_BOUND (TYPE_INDEX_TYPE (arraytype)) ++/* TYPE_BYTE_STRIDE (TYPE_INDEX_TYPE (arraytype)) with a fallback to the ++ element size if no specific stride value is known. */ ++#define TYPE_ARRAY_BYTE_STRIDE_VALUE(arraytype) \ ++ (TYPE_BYTE_STRIDE (TYPE_INDEX_TYPE (arraytype)) == 0 \ ++ ? TYPE_LENGTH (TYPE_TARGET_TYPE (arraytype)) \ ++ : TYPE_BYTE_STRIDE (TYPE_INDEX_TYPE (arraytype))) + + /* C++ */ + +@@ -1078,6 +1156,16 @@ extern struct type *builtin_type_error; + (TYPE_UNSIGNED(t) ? UMIN_OF_SIZE(TYPE_LENGTH(t)) \ + : MIN_OF_SIZE(TYPE_LENGTH(t))) + ++/* Virtual OBJFILE used for builtin types. */ ++#define OBJFILE_INTERNAL ((struct objfile *) 1L) ++ ++/* Virtual OBJFILE used for types allocated by malloc. FIXME: Currently ++ backward compatible with the old NULL value; fix then also init_type. */ ++#define OBJFILE_MALLOC ((struct objfile *) 0L) ++ ++#define OBJFILE_IS_VIRTUAL(objfile) ((objfile) == OBJFILE_INTERNAL \ ++ || (objfile) == OBJFILE_MALLOC) ++ + /* Allocate space for storing data associated with a particular type. + We ensure that the space is allocated using the same mechanism that + was used to allocate the space for the type structure itself. I.E. +@@ -1087,18 +1175,18 @@ extern struct type *builtin_type_error; + builtin types), then the data space will be allocated with xmalloc, + the same as for the type structure. */ + +-#define TYPE_ALLOC(t,size) \ +- (TYPE_OBJFILE (t) != NULL \ +- ? obstack_alloc (&TYPE_OBJFILE (t) -> objfile_obstack, size) \ +- : xmalloc (size)) ++#define TYPE_ALLOC(t,size) \ ++ (OBJFILE_IS_VIRTUAL (TYPE_OBJFILE (t)) \ ++ ? xmalloc (size) \ ++ : obstack_alloc (&TYPE_OBJFILE (t) -> objfile_obstack, size)) + +-#define TYPE_ZALLOC(t,size) \ +- (TYPE_OBJFILE (t) != NULL \ +- ? memset (obstack_alloc (&TYPE_OBJFILE (t)->objfile_obstack, size), \ +- 0, size) \ +- : xzalloc (size)) ++#define TYPE_ZALLOC(t,size) \ ++ (OBJFILE_IS_VIRTUAL (TYPE_OBJFILE (t)) \ ++ ? xzalloc (size) \ ++ : memset (obstack_alloc (&TYPE_OBJFILE (t)->objfile_obstack, size), \ ++ 0, size)) + +-extern struct type *alloc_type (struct objfile *); ++extern struct type *alloc_type (struct objfile *, struct type *); + + extern struct type *init_type (enum type_code, int, int, char *, + struct objfile *); +@@ -1172,6 +1260,18 @@ extern struct type *create_range_type (struct type *, struct type *, int, + extern struct type *create_array_type (struct type *, struct type *, + struct type *); + ++extern CORE_ADDR type_range_any_field_internal (struct type *range_type, ++ int fieldno); ++ ++extern int type_range_high_bound_internal (struct type *range_type); ++ ++extern int type_range_count_bound_internal (struct type *range_type); ++ ++extern CORE_ADDR type_range_byte_stride_internal (struct type *range_type, ++ struct type *element_type); ++ ++extern void finalize_type (struct type *type); ++ + extern struct type *create_string_type (struct type *, struct type *); + + extern struct type *create_set_type (struct type *, struct type *); +@@ -1263,10 +1363,15 @@ extern void maintenance_print_type (char *, int); + + extern htab_t create_copied_types_hash (struct objfile *objfile); + +-extern struct type *copy_type_recursive (struct objfile *objfile, +- struct type *type, ++extern struct type *copy_type_recursive (struct type *type, + htab_t copied_types); + + extern struct type *copy_type (const struct type *type); + ++extern void type_incref (struct type *type); ++ ++extern void type_decref (struct type *type); ++ ++extern void free_all_types (void); ++ + #endif /* GDBTYPES_H */ +diff --git a/gdb/gnu-v2-abi.c b/gdb/gnu-v2-abi.c +index 7cacac1..a456228 100644 +--- a/gdb/gnu-v2-abi.c ++++ b/gdb/gnu-v2-abi.c +@@ -242,7 +242,7 @@ gnuv2_value_rtti_type (struct value *v, int *full, int *top, int *using_enc) + we'd waste a bunch of time figuring out we already know the type. + Besides, we don't care about the type, just the actual pointer + */ +- if (VALUE_ADDRESS (value_field (v, known_type_vptr_fieldno)) == 0) ++ if (value_address (value_field (v, known_type_vptr_fieldno)) == 0) + return NULL; + + vtbl = value_as_address (value_field (v, known_type_vptr_fieldno)); +diff --git a/gdb/gnu-v3-abi.c b/gdb/gnu-v3-abi.c +index 3a52df3..6cdf716 100644 +--- a/gdb/gnu-v3-abi.c ++++ b/gdb/gnu-v3-abi.c +@@ -269,8 +269,7 @@ gnuv3_rtti_type (struct value *value, + + /* Find the linker symbol for this vtable. */ + vtable_symbol +- = lookup_minimal_symbol_by_pc (VALUE_ADDRESS (vtable) +- + value_offset (vtable) ++ = lookup_minimal_symbol_by_pc (value_address (vtable) + + value_embedded_offset (vtable)); + if (! vtable_symbol) + return NULL; +@@ -487,10 +486,8 @@ gnuv3_find_method_in (struct type *domain, CORE_ADDR voffset, + LONGEST adjustment) + { + int i; +- const char *physname; + + /* Search this class first. */ +- physname = NULL; + if (adjustment == 0) + { + int len; +@@ -615,13 +612,15 @@ gnuv3_print_method_ptr (const gdb_byte *contents, + { + char *demangled_name = cplus_demangle (physname, + DMGL_ANSI | DMGL_PARAMS); +- if (demangled_name != NULL) ++ fprintf_filtered (stream, "&virtual "); ++ if (demangled_name == NULL) ++ fputs_filtered (physname, stream); ++ else + { +- fprintf_filtered (stream, "&virtual "); + fputs_filtered (demangled_name, stream); + xfree (demangled_name); +- return; + } ++ return; + } + } + +diff --git a/gdb/i386-linux-nat.c b/gdb/i386-linux-nat.c +index 2366474..f83de32 100644 +--- a/gdb/i386-linux-nat.c ++++ b/gdb/i386-linux-nat.c +@@ -751,7 +751,13 @@ i386_linux_resume (struct target_ops *ops, + { + int pid = PIDGET (ptid); + +- int request = PTRACE_CONT; ++ int request; ++ ++ if (target_passed_by_entrypoint () > 0 ++ && catch_syscall_enabled () > 0) ++ request = PTRACE_SYSCALL; ++ else ++ request = PTRACE_CONT; + + if (step) + { +diff --git a/gdb/i386-linux-tdep.c b/gdb/i386-linux-tdep.c +index 1a2e4f0..973eced 100644 +--- a/gdb/i386-linux-tdep.c ++++ b/gdb/i386-linux-tdep.c +@@ -37,6 +37,10 @@ + #include "symtab.h" + #include "arch-utils.h" + #include "regset.h" ++#include "linux-tdep.h" ++ ++/* The syscall's XML filename for i386. */ ++#define XML_SYSCALL_FILENAME_I386 "syscalls/i386-linux.xml" + + /* Supported register note sections. */ + static struct core_regset_section i386_linux_regset_sections[] = +@@ -349,6 +353,26 @@ i386_linux_write_pc (struct regcache *regcache, CORE_ADDR pc) + } + + ++static LONGEST ++i386_linux_get_syscall_number (struct gdbarch *gdbarch, ++ ptid_t ptid) ++{ ++ struct regcache *regcache = get_thread_regcache (ptid); ++ /* The content of a register. */ ++ gdb_byte buf[4]; ++ /* The result. */ ++ LONGEST ret; ++ ++ /* Getting the system call number from the register. ++ When dealing with x86 architecture, this information ++ is stored at %eax register. */ ++ regcache_cooked_read (regcache, I386_LINUX_ORIG_EAX_REGNUM, buf); ++ ++ ret = extract_signed_integer (buf, 4); ++ ++ return ret; ++} ++ + /* The register sets used in GNU/Linux ELF core-dumps are identical to + the register sets in `struct user' that are used for a.out + core-dumps. These are also used by ptrace(2). The corresponding +@@ -419,6 +443,9 @@ i386_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) + { + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + ++ /* Initializing common functions. */ ++ linux_tdep_init (gdbarch); ++ + /* GNU/Linux uses ELF. */ + i386_elf_init_abi (info, gdbarch); + +@@ -472,6 +499,11 @@ i386_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) + displaced_step_at_entry_point); + + set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type); ++ ++ /* Functions for 'catch syscall'. */ ++ set_gdbarch_xml_syscall_filename (gdbarch, XML_SYSCALL_FILENAME_I386); ++ set_gdbarch_get_syscall_number (gdbarch, ++ i386_linux_get_syscall_number); + } + + /* Provide a prototype to silence -Wmissing-prototypes. */ +diff --git a/gdb/inf-child.c b/gdb/inf-child.c +index 38311f1..fc968cf 100644 +--- a/gdb/inf-child.c ++++ b/gdb/inf-child.c +@@ -148,6 +148,15 @@ inf_child_remove_exec_catchpoint (int pid) + } + + static int ++inf_child_set_syscall_catchpoint (int pid, int needed, int any_count, ++ int table_size, int *table) ++{ ++ /* This version of Unix doesn't support notification of syscall ++ events. */ ++ return 0; ++} ++ ++static int + inf_child_can_run (void) + { + return 1; +@@ -190,6 +199,7 @@ inf_child_target (void) + t->to_follow_fork = inf_child_follow_fork; + t->to_insert_exec_catchpoint = inf_child_insert_exec_catchpoint; + t->to_remove_exec_catchpoint = inf_child_remove_exec_catchpoint; ++ t->to_set_syscall_catchpoint = inf_child_set_syscall_catchpoint; + t->to_can_run = inf_child_can_run; + t->to_pid_to_exec_file = inf_child_pid_to_exec_file; + t->to_stratum = process_stratum; +diff --git a/gdb/inf-ptrace.c b/gdb/inf-ptrace.c +index f40b6b7..ff429c4 100644 +--- a/gdb/inf-ptrace.c ++++ b/gdb/inf-ptrace.c +@@ -356,13 +356,19 @@ inf_ptrace_resume (struct target_ops *ops, + ptid_t ptid, int step, enum target_signal signal) + { + pid_t pid = ptid_get_pid (ptid); +- int request = PT_CONTINUE; ++ int request; + + if (pid == -1) + /* Resume all threads. Traditionally ptrace() only supports + single-threaded processes, so simply resume the inferior. */ + pid = ptid_get_pid (inferior_ptid); + ++ if (target_passed_by_entrypoint () > 0 ++ && catch_syscall_enabled () > 0) ++ request = PT_SYSCALL; ++ else ++ request = PT_CONTINUE; ++ + if (step) + { + /* If this system does not support PT_STEP, a higher level +diff --git a/gdb/infcall.c b/gdb/infcall.c +index d6da8b2..80168b3 100644 +--- a/gdb/infcall.c ++++ b/gdb/infcall.c +@@ -98,6 +98,28 @@ Unwinding of stack if a signal is received while in a call dummy is %s.\n"), + value); + } + ++/* This boolean tells what gdb should do if a std::terminate call is ++ made while in a function called from gdb (call dummy). ++ As the confines of a single dummy stack prohibit out-of-frame ++ handlers from handling a raised exception, and as out-of-frame ++ handlers are common in C++, this can lead to no handler being found ++ by the unwinder, and a std::terminate call. This is a false positive. ++ If set, gdb unwinds the stack and restores the context to what it ++ was before the call. ++ ++ The default is to unwind the frame if a std::terminate call is made.. */ ++ ++static int unwind_on_terminating_exception_p = 1; ++static void ++show_unwind_on_terminating_exception_p (struct ui_file *file, int from_tty, ++ struct cmd_list_element *c, ++ const char *value) ++ ++{ ++ fprintf_filtered (file, _("\ ++Unwind stack if a C++ exception is unhandled while in a call dummy is %s.\n"), ++ value); ++} + + /* Perform the standard coercions that are specified + for arguments to be passed to C or Ada functions. +@@ -217,7 +239,7 @@ find_function_addr (struct value *function, struct type **retval_type) + /* Determine address to call. */ + if (code == TYPE_CODE_FUNC || code == TYPE_CODE_METHOD) + { +- funaddr = VALUE_ADDRESS (function); ++ funaddr = value_address (function); + value_type = TYPE_TARGET_TYPE (ftype); + } + else if (code == TYPE_CODE_PTR) +@@ -419,6 +441,8 @@ call_function_by_hand (struct value *function, int nargs, struct value **args) + struct cleanup *args_cleanup; + struct frame_info *frame; + struct gdbarch *gdbarch; ++ struct breakpoint *terminate_bp = 0; ++ struct minimal_symbol *tm; + ptid_t call_thread_ptid; + struct gdb_exception e; + const char *name; +@@ -718,6 +742,29 @@ call_function_by_hand (struct value *function, int nargs, struct value **args) + bpt = set_momentary_breakpoint (sal, dummy_id, bp_call_dummy); + bpt->disposition = disp_del; + } ++ ++ /* Create a breakpoint in std::terminate. ++ If a C++ exception is raised in the dummy-frame, and the ++ exception handler is (normally, and expected to be) out-of-frame, ++ the default C++ handler will (wrongly) be called in an inferior ++ function call. This is wrong, as an exception can be normally ++ and legally handled out-of-frame. The confines of the dummy frame ++ prevent the unwinder from finding the correct handler (or any ++ handler, unless it is in-frame). The default handler calls ++ std::terminate. This will kill the inferior. Assert that ++ terminate should never be called in an inferior function ++ call. Place a momentary breakpoint in the std::terminate function ++ and if triggered in the call, rewind */ ++ if (unwind_on_terminating_exception_p) ++ { ++ tm = lookup_minimal_symbol ("std::terminate()", NULL, NULL); ++ if (tm != NULL) ++ { ++ terminate_bp = set_momentary_breakpoint_at_pc ++ (SYMBOL_VALUE_ADDRESS (tm), bp_breakpoint); ++ make_cleanup_delete_breakpoint (terminate_bp); ++ } ++ } + + /* Everything's ready, push all the info needed to restore the + caller (and identify the dummy-frame) onto the dummy-frame +@@ -828,6 +875,16 @@ When the function is done executing, GDB will silently stop."), + name); + } + ++ if (! target_has_execution) ++ { ++ /* If we try to restore the inferior status (via the cleanup), ++ we'll crash as the inferior is no longer running. */ ++ discard_cleanups (inf_status_cleanup); ++ discard_inferior_status (inf_status); ++ error (_("\ ++The program being debugged exited while in a function called from GDB.")); ++ } ++ + if (stopped_by_random_signal || !stop_stack_dummy) + { + const char *name = get_function_name (funaddr, +@@ -884,6 +941,38 @@ When the function is done executing, GDB will silently stop."), + + if (!stop_stack_dummy) + { ++ ++ /* Check if unwind on terminating exception behaviour is on */ ++ if (unwind_on_terminating_exception_p) ++ { ++ /* Check that the breakpoint is our special std::terminate ++ breakpoint. If it is, we do not want to kill the inferior ++ in an inferior function call. Rewind, and warn the user */ ++ ++ if ((terminate_bp != NULL) && ++ (inferior_thread()->stop_bpstat->breakpoint_at->address ++ == terminate_bp->loc->address)) ++ ++ ++ { ++ ++ /* We must get back to the frame we were before the ++ dummy call. */ ++ dummy_frame_pop (dummy_id); ++ ++ /* We also need to restore inferior status to that before the ++ dummy call. */ ++ restore_inferior_status (inf_status); ++ ++ error (_("\ ++The program being debugged entered a std::terminate call which would\n\ ++have terminated the program being debugged. GDB has restored the\n\ ++context to what it was before the call\n\ ++To change this behaviour use \"set unwind-on-terminating-exception off\"\n\ ++Evaluation of the expression containing the function (%s) will be abandoned."), ++ name); ++ } ++ } + /* We hit a breakpoint inside the FUNCTION. + Keep the dummy frame, the user may want to examine its state. + Discard inferior status, we're not at the same point +@@ -992,4 +1081,19 @@ The default is to stop in the frame where the signal was received."), + NULL, + show_unwind_on_signal_p, + &setlist, &showlist); ++ ++ add_setshow_boolean_cmd ("unwind-on-terminating-exception", no_class, ++ &unwind_on_terminating_exception_p, _("\ ++Set unwinding of stack if a std::terminate() call originates from\n\ ++the default C++ exception handler."), _("\ ++Show unwinding of stack if a std::terminate() call originates from\n\ ++the default C++ exception handler."), _("\ ++The unwind on terminating exception flag lets the user determine\n\ ++what gdb should do if a std::terminate() call is made from the\n\ ++default exception handler.\n\ ++The default is to unwind the frame."), ++ NULL, ++ show_unwind_on_terminating_exception_p, ++ &setlist, &showlist); ++ + } +diff --git a/gdb/infcmd.c b/gdb/infcmd.c +index 0a17dab..d48f4b1 100644 +--- a/gdb/infcmd.c ++++ b/gdb/infcmd.c +@@ -466,6 +466,11 @@ run_command_1 (char *args, int from_tty, int tbreak_at_main) + init_wait_for_inferior (); + clear_breakpoint_hit_counts (); + ++ /* If we already caught a syscall catchpoint, then reset its ++ syscall_number information because we are starting all over ++ again. */ ++ clear_syscall_catchpoints_info (); ++ + /* Clean up any leftovers from other runs. Some other things from + this function should probably be moved into target_pre_inferior. */ + target_pre_inferior (from_tty); +diff --git a/gdb/infrun.c b/gdb/infrun.c +index ee5f987..2f627ea 100644 +--- a/gdb/infrun.c ++++ b/gdb/infrun.c +@@ -1046,7 +1046,7 @@ a command like `return' or `jump' to continue execution.")); + } + } + +- /* If there were any forks/vforks/execs that were caught and are ++ /* If there were any forks/vforks/execs/syscalls that were caught and are + now to be followed, then do so. */ + switch (pending_follow.kind) + { +@@ -1069,6 +1069,11 @@ a command like `return' or `jump' to continue execution.")); + pending_follow.kind = TARGET_WAITKIND_SPURIOUS; + break; + ++ case TARGET_WAITKIND_SYSCALL_ENTRY: ++ case TARGET_WAITKIND_SYSCALL_RETURN: ++ pending_follow.kind = TARGET_WAITKIND_SPURIOUS; ++ break; ++ + default: + break; + } +@@ -1509,7 +1514,7 @@ init_wait_for_inferior (void) + + breakpoint_init_inferior (inf_starting); + +- /* The first resume is not following a fork/vfork/exec. */ ++ /* The first resume is not following a fork/vfork/exec/syscall. */ + pending_follow.kind = TARGET_WAITKIND_SPURIOUS; /* I.e., none. */ + + clear_proceed_status (); +@@ -2155,6 +2160,50 @@ ensure_not_running (void) + error_is_running (); + } + ++/* Auxiliary function that handles syscall entry/return events. ++ It returns 1 if the inferior should keep going (and GDB ++ should ignore the event), or 0 if the event deserves to be ++ processed. */ ++static int ++deal_with_syscall_event (struct execution_control_state *ecs) ++{ ++ int syscall_number = gdbarch_get_syscall_number (current_gdbarch, ++ ecs->ptid); ++ if (catch_syscall_enabled () > 0 ++ && catching_syscall_number (syscall_number) > 0) ++ { ++ ecs->event_thread->stop_signal = TARGET_SIGNAL_TRAP; ++ pending_follow.kind = ecs->ws.kind; ++ ++ if (!ptid_equal (ecs->ptid, inferior_ptid)) ++ { ++ context_switch (ecs->ptid); ++ reinit_frame_cache (); ++ } ++ ++ stop_pc = read_pc (); ++ ++ ecs->event_thread->stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid); ++ ++ ecs->random_signal = !bpstat_explains_signal (ecs->event_thread->stop_bpstat); ++ ++ /* If no catchpoint triggered for this, then keep going. */ ++ if (ecs->random_signal) ++ { ++ ecs->event_thread->stop_signal = TARGET_SIGNAL_0; ++ keep_going (ecs); ++ return 1; ++ } ++ return 0; ++ } ++ else ++ { ++ resume (0, TARGET_SIGNAL_0); ++ prepare_to_wait (ecs); ++ return 1; ++ } ++} ++ + /* Given an execution control state that has been freshly filled in + by an event from the inferior, figure out what it means and take + appropriate action. */ +@@ -2449,9 +2498,11 @@ handle_inferior_event (struct execution_control_state *ecs) + case TARGET_WAITKIND_SYSCALL_ENTRY: + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_SYSCALL_ENTRY\n"); +- resume (0, TARGET_SIGNAL_0); +- prepare_to_wait (ecs); +- return; ++ /* Getting the current syscall number */ ++ if (deal_with_syscall_event (ecs) != 0) ++ return; ++ goto process_event_stop_test; ++ break; + + /* Before examining the threads further, step this thread to + get it entirely out of the syscall. (We get notice of the +@@ -2461,9 +2512,10 @@ handle_inferior_event (struct execution_control_state *ecs) + case TARGET_WAITKIND_SYSCALL_RETURN: + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_SYSCALL_RETURN\n"); +- target_resume (ecs->ptid, 1, TARGET_SIGNAL_0); +- prepare_to_wait (ecs); +- return; ++ if (deal_with_syscall_event (ecs) != 0) ++ return; ++ goto process_event_stop_test; ++ break; + + case TARGET_WAITKIND_STOPPED: + if (debug_infrun) +@@ -5166,6 +5218,25 @@ inferior_has_execd (ptid_t pid, char **execd_pathname) + return 1; + } + ++int ++inferior_has_called_syscall (ptid_t pid, int *syscall_number) ++{ ++ struct target_waitstatus last; ++ ptid_t last_ptid; ++ ++ get_last_target_status (&last_ptid, &last); ++ ++ if (last.kind != TARGET_WAITKIND_SYSCALL_ENTRY && ++ last.kind != TARGET_WAITKIND_SYSCALL_RETURN) ++ return 0; ++ ++ if (!ptid_equal (last_ptid, pid)) ++ return 0; ++ ++ *syscall_number = last.value.syscall_number; ++ return 1; ++} ++ + /* Oft used ptids */ + ptid_t null_ptid; + ptid_t minus_one_ptid; +diff --git a/gdb/jv-lang.c b/gdb/jv-lang.c +index b702ebf..a211adf 100644 +--- a/gdb/jv-lang.c ++++ b/gdb/jv-lang.c +@@ -61,7 +61,8 @@ static char *get_java_utf8_name (struct obstack *obstack, struct value *name); + static int java_class_is_primitive (struct value *clas); + static struct value *java_value_string (char *ptr, int len); + +-static void java_emit_char (int c, struct ui_file * stream, int quoter); ++static void java_emit_char (int c, struct type *type, ++ struct ui_file * stream, int quoter); + + static char *java_class_name_from_physname (const char *physname); + +@@ -210,8 +211,7 @@ get_java_utf8_name (struct obstack *obstack, struct value *name) + CORE_ADDR data_addr; + temp = value_struct_elt (&temp, NULL, "length", NULL, "structure"); + name_length = (int) value_as_long (temp); +- data_addr = VALUE_ADDRESS (temp) + value_offset (temp) +- + TYPE_LENGTH (value_type (temp)); ++ data_addr = value_address (temp) + TYPE_LENGTH (value_type (temp)); + chrs = obstack_alloc (obstack, name_length + 1); + chrs[name_length] = '\0'; + read_memory (data_addr, (gdb_byte *) chrs, name_length); +@@ -266,7 +266,7 @@ type_from_class (struct value *clas) + return NULL; + clas = value_ind (clas); + } +- addr = VALUE_ADDRESS (clas) + value_offset (clas); ++ addr = value_address (clas); + + #if 0 + get_java_class_symtab (); +@@ -302,7 +302,7 @@ type_from_class (struct value *clas) + if (type != NULL) + return type; + +- type = alloc_type (objfile); ++ type = alloc_type (objfile, NULL); + TYPE_CODE (type) = TYPE_CODE_STRUCT; + INIT_CPLUS_SPECIFIC (type); + +@@ -422,7 +422,7 @@ java_link_class_type (struct type *type, struct value *clas) + fields = NULL; + nfields--; /* First set up dummy "class" field. */ + SET_FIELD_PHYSADDR (TYPE_FIELD (type, nfields), +- VALUE_ADDRESS (clas) + value_offset (clas)); ++ value_address (clas)); + TYPE_FIELD_NAME (type, nfields) = "class"; + TYPE_FIELD_TYPE (type, nfields) = value_type (clas); + SET_TYPE_FIELD_PRIVATE (type, nfields); +@@ -439,7 +439,9 @@ java_link_class_type (struct type *type, struct value *clas) + } + else + { /* Re-use field value for next field. */ +- VALUE_ADDRESS (field) += TYPE_LENGTH (value_type (field)); ++ CORE_ADDR addr ++ = value_address (field) + TYPE_LENGTH (value_type (field)); ++ set_value_address (field, addr); + set_value_lazy (field, 1); + } + temp = field; +@@ -509,7 +511,9 @@ java_link_class_type (struct type *type, struct value *clas) + } + else + { /* Re-use method value for next method. */ +- VALUE_ADDRESS (method) += TYPE_LENGTH (value_type (method)); ++ CORE_ADDR addr ++ = value_address (method) + TYPE_LENGTH (value_type (method)); ++ set_value_address (method, addr); + set_value_lazy (method, 1); + } + +@@ -796,7 +800,7 @@ java_value_string (char *ptr, int len) + characters and strings is language specific. */ + + static void +-java_emit_char (int c, struct ui_file *stream, int quoter) ++java_emit_char (int c, struct type *type, struct ui_file *stream, int quoter) + { + switch (c) + { +diff --git a/gdb/jv-valprint.c b/gdb/jv-valprint.c +index d3606fd..cdcb440 100644 +--- a/gdb/jv-valprint.c ++++ b/gdb/jv-valprint.c +@@ -45,7 +45,7 @@ java_value_print (struct value *val, struct ui_file *stream, + struct value_print_options opts; + + type = value_type (val); +- address = VALUE_ADDRESS (val) + value_offset (val); ++ address = value_address (val); + + if (is_object_type (type)) + { +@@ -143,8 +143,8 @@ java_value_print (struct value *val, struct ui_file *stream, + struct value *v = allocate_value (el_type); + struct value *next_v = allocate_value (el_type); + +- VALUE_ADDRESS (v) = address + JAVA_OBJECT_SIZE + 4; +- VALUE_ADDRESS (next_v) = VALUE_ADDRESS (v); ++ set_value_address (v, address + JAVA_OBJECT_SIZE + 4); ++ set_value_address (next_v, value_raw_address (v)); + + while (i < length && things_printed < options->print_max) + { +@@ -230,7 +230,7 @@ java_value_print (struct value *val, struct ui_file *stream, + + value_free_to_mark (mark); /* Release unnecessary values */ + +- val_print_string (data + boffset, count, 2, stream, options); ++ val_print_string (java_char_type, data + boffset, count, stream, options); + + return 0; + } +@@ -520,7 +520,7 @@ java_val_print (struct type *type, const gdb_byte *valaddr, + || (TYPE_CODE (type) == TYPE_CODE_INT + && TYPE_LENGTH (type) == 2 + && strcmp (TYPE_NAME (type), "char") == 0)) +- LA_PRINT_CHAR ((int) unpack_long (type, valaddr), stream); ++ LA_PRINT_CHAR ((int) unpack_long (type, valaddr), type, stream); + else + val_print_type_code_int (type, valaddr, stream); + break; +diff --git a/gdb/language.c b/gdb/language.c +index 3c37a64..6209d7f 100644 +--- a/gdb/language.c ++++ b/gdb/language.c +@@ -65,9 +65,11 @@ static void set_check (char *, int); + + static void set_type_range_case (void); + +-static void unk_lang_emit_char (int c, struct ui_file *stream, int quoter); ++static void unk_lang_emit_char (int c, struct type *type, ++ struct ui_file *stream, int quoter); + +-static void unk_lang_printchar (int c, struct ui_file *stream); ++static void unk_lang_printchar (int c, struct type *type, ++ struct ui_file *stream); + + static void unk_lang_print_type (struct type *, char *, struct ui_file *, + int, int); +@@ -1065,20 +1067,22 @@ unk_lang_error (char *msg) + } + + static void +-unk_lang_emit_char (int c, struct ui_file *stream, int quoter) ++unk_lang_emit_char (int c, struct type *type, struct ui_file *stream, ++ int quoter) + { + error (_("internal error - unimplemented function unk_lang_emit_char called.")); + } + + static void +-unk_lang_printchar (int c, struct ui_file *stream) ++unk_lang_printchar (int c, struct type *type, struct ui_file *stream) + { + error (_("internal error - unimplemented function unk_lang_printchar called.")); + } + + static void +-unk_lang_printstr (struct ui_file *stream, const gdb_byte *string, +- unsigned int length, int width, int force_ellipses, ++unk_lang_printstr (struct ui_file *stream, struct type *type, ++ const gdb_byte *string, unsigned int length, ++ int force_ellipses, + const struct value_print_options *options) + { + error (_("internal error - unimplemented function unk_lang_printstr called.")); +diff --git a/gdb/language.h b/gdb/language.h +index 85826fd..e5f80ab 100644 +--- a/gdb/language.h ++++ b/gdb/language.h +@@ -186,14 +186,15 @@ struct language_defn + + void (*la_post_parser) (struct expression ** expp, int void_context_p); + +- void (*la_printchar) (int ch, struct ui_file * stream); ++ void (*la_printchar) (int ch, struct type *chtype, struct ui_file * stream); + +- void (*la_printstr) (struct ui_file * stream, const gdb_byte *string, +- unsigned int length, int width, ++ void (*la_printstr) (struct ui_file * stream, struct type *elttype, ++ const gdb_byte *string, unsigned int length, + int force_ellipses, + const struct value_print_options *); + +- void (*la_emitchar) (int ch, struct ui_file * stream, int quoter); ++ void (*la_emitchar) (int ch, struct type *chtype, ++ struct ui_file * stream, int quoter); + + /* Print a type using syntax appropriate for this language. */ + +@@ -381,13 +382,13 @@ extern enum language set_language (enum language); + #define LA_VALUE_PRINT(val,stream,options) \ + (current_language->la_value_print(val,stream,options)) + +-#define LA_PRINT_CHAR(ch, stream) \ +- (current_language->la_printchar(ch, stream)) +-#define LA_PRINT_STRING(stream, string, length, width, force_ellipses,options) \ +- (current_language->la_printstr(stream, string, length, width, \ ++#define LA_PRINT_CHAR(ch, type, stream) \ ++ (current_language->la_printchar(ch, type, stream)) ++#define LA_PRINT_STRING(stream, elttype, string, length, force_ellipses,options) \ ++ (current_language->la_printstr(stream, elttype, string, length, \ + force_ellipses,options)) +-#define LA_EMIT_CHAR(ch, stream, quoter) \ +- (current_language->la_emitchar(ch, stream, quoter)) ++#define LA_EMIT_CHAR(ch, type, stream, quoter) \ ++ (current_language->la_emitchar(ch, type, stream, quoter)) + #define LA_GET_STRING(value, buffer, length, encoding) \ + (current_language->la_get_string(value, buffer, length, encoding)) + +diff --git a/gdb/linespec.c b/gdb/linespec.c +index 6579d42..b3ae6c0 100644 +--- a/gdb/linespec.c ++++ b/gdb/linespec.c +@@ -842,13 +842,33 @@ decode_line_1 (char **argptr, int funfirstline, struct symtab *default_symtab, + } + else if (paren_pointer != NULL) + { +- p = paren_pointer + 1; ++ /* We need to deal with method and function overloads ++ with no parameters. Gdb and gcc (and who knows about other ++ compilers) are very inconsistent with the keyword "void". ++ Canonicalizing C++ types is insufficient in this case, since ++ we still need to enforce the presence (or lack thereof) of ++ "void". For simplicity, omit the keyword "void" if present. */ ++ if (strncmp (paren_pointer - 5, "(void)", 6) == 0) ++ { ++ char *a, *b; ++ a = paren_pointer - 4; ++ b = paren_pointer; ++ while ((*(a++) = *(b++)) != '\0') ; ++ *a = '\0'; ++ p = paren_pointer - 3; ++ } ++ else ++ p = paren_pointer + 1; + } + else + { + p = skip_quoted (*argptr); + } + ++ /* Make sure we keep important kewords like "const" */ ++ if (strncmp (p, " const", 6) == 0) ++ p += 6; ++ + copy = (char *) alloca (p - *argptr + 1); + memcpy (copy, *argptr, p - *argptr); + copy[p - *argptr] = '\0'; +diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c +index 12b786e..e30bf9a 100644 +--- a/gdb/linux-nat.c ++++ b/gdb/linux-nat.c +@@ -61,6 +61,10 @@ + # endif + #endif /* HAVE_PERSONALITY */ + ++/* To be used when one needs to know wether a ++ WSTOPSIG (status) is a syscall */ ++#define TRAP_IS_SYSCALL (SIGTRAP | 0x80) ++ + /* This comment documents high-level logic of this file. + + Waiting for events in sync mode +@@ -281,17 +285,29 @@ struct simple_pid_list *stopped_pids; + + static int linux_supports_tracefork_flag = -1; + ++/* This variable is a tri-state flag: -1 for unknown, 0 if PTRACE_O_TRACESYSGOOD ++ can not be used, 1 if it can. */ ++ ++static int linux_supports_tracesysgood_flag = -1; ++ + /* If we have PTRACE_O_TRACEFORK, this flag indicates whether we also have + PTRACE_O_TRACEVFORKDONE. */ + + static int linux_supports_tracevforkdone_flag = -1; + ++/* If the inferior have passed through its entrypoint (AT_ENTRY), ++ then this flag is set to 1. Otherwise, its value is 0. */ ++static int linux_passed_by_entrypoint_flag = 0; ++ + /* Async mode support */ + + /* Zero if the async mode, although enabled, is masked, which means + linux_nat_wait should behave as if async mode was off. */ + static int linux_nat_async_mask_value = 1; + ++/* Stores the current used ptrace() options. */ ++static int current_ptrace_options = 0; ++ + /* The read/write ends of the pipe registered as waitable file in the + event loop. */ + static int linux_nat_event_pipe[2] = { -1, -1 }; +@@ -636,6 +652,41 @@ linux_test_for_tracefork (int original_pid) + linux_nat_async_events (async_events_original_state); + } + ++/* Determine if PTRACE_O_TRACESYSGOOD can be used to follow syscalls. ++ ++ We try to enable syscall tracing on ORIGINAL_PID. If this fails, ++ we know that the feature is not available. This may change the tracing ++ options for ORIGINAL_PID, but we'll be setting them shortly anyway. */ ++ ++static void ++linux_test_for_tracesysgood (int original_pid) ++{ ++ int ret; ++ enum sigchld_state async_events_original_state; ++ ++ async_events_original_state = linux_nat_async_events (sigchld_sync); ++ ++ linux_supports_tracesysgood_flag = 0; ++ ++ ret = ptrace (PTRACE_SETOPTIONS, original_pid, 0, PTRACE_O_TRACESYSGOOD); ++ if (ret != 0) ++ return; ++ ++ linux_supports_tracesysgood_flag = 1; ++ linux_nat_async_events (async_events_original_state); ++} ++ ++/* Determine wether we support PTRACE_O_TRACESYSGOOD option available. ++ This function also sets linux_supports_tracesysgood_flag. */ ++ ++static int ++linux_supports_tracesysgood (int pid) ++{ ++ if (linux_supports_tracesysgood_flag == -1) ++ linux_test_for_tracesysgood (pid); ++ return linux_supports_tracesysgood_flag; ++} ++ + /* Return non-zero iff we have tracefork functionality available. + This function also sets linux_supports_tracefork_flag. */ + +@@ -655,12 +706,34 @@ linux_supports_tracevforkdone (int pid) + return linux_supports_tracevforkdone_flag; + } + ++static void ++linux_enable_tracesysgood (ptid_t ptid) ++{ ++ int pid = ptid_get_lwp (ptid); ++ ++ if (pid == 0) ++ pid = ptid_get_pid (ptid); ++ ++ if (linux_supports_tracesysgood (pid) == 0) ++ return; ++ ++ current_ptrace_options |= PTRACE_O_TRACESYSGOOD; ++ linux_passed_by_entrypoint_flag = 1; ++ ++ ptrace (PTRACE_SETOPTIONS, pid, 0, current_ptrace_options); ++} ++ ++static int ++linux_passed_by_entrypoint (void) ++{ ++ return linux_passed_by_entrypoint_flag; ++} ++ + + void + linux_enable_event_reporting (ptid_t ptid) + { + int pid = ptid_get_lwp (ptid); +- int options; + + if (pid == 0) + pid = ptid_get_pid (ptid); +@@ -668,15 +741,16 @@ linux_enable_event_reporting (ptid_t ptid) + if (! linux_supports_tracefork (pid)) + return; + +- options = PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK | PTRACE_O_TRACEEXEC +- | PTRACE_O_TRACECLONE; ++ current_ptrace_options |= PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK ++ | PTRACE_O_TRACEEXEC | PTRACE_O_TRACECLONE; ++ + if (linux_supports_tracevforkdone (pid)) +- options |= PTRACE_O_TRACEVFORKDONE; ++ current_ptrace_options |= PTRACE_O_TRACEVFORKDONE; + + /* Do not enable PTRACE_O_TRACEEXIT until GDB is more prepared to support + read-only process state. */ + +- ptrace (PTRACE_SETOPTIONS, pid, 0, options); ++ ptrace (PTRACE_SETOPTIONS, pid, 0, current_ptrace_options); + } + + static void +@@ -684,6 +758,7 @@ linux_child_post_attach (int pid) + { + linux_enable_event_reporting (pid_to_ptid (pid)); + check_for_thread_db (); ++ linux_enable_tracesysgood (pid_to_ptid (pid)); + } + + static void +@@ -691,6 +766,7 @@ linux_child_post_startup_inferior (ptid_t ptid) + { + linux_enable_event_reporting (ptid); + check_for_thread_db (); ++ linux_enable_tracesysgood (ptid); + } + + static int +@@ -931,6 +1007,16 @@ linux_child_insert_exec_catchpoint (int pid) + error (_("Your system does not support exec catchpoints.")); + } + ++static int ++linux_child_set_syscall_catchpoint (int pid, int needed, int any_count, ++ int table_size, int *table) ++{ ++ if (! linux_supports_tracesysgood (pid)) ++ error (_("Your system does not support syscall catchpoints.")); ++ /* We ignore the arguments. */ ++ return 0; ++} ++ + /* On GNU/Linux there are no real LWP's. The closest thing to LWP's + are processes sharing the same VM space. A multi-threaded process + is basically a group of such processes. However, such a grouping +@@ -1352,6 +1438,9 @@ linux_nat_create_inferior (struct target_ops *ops, + int personality_orig = 0, personality_set = 0; + #endif /* HAVE_PERSONALITY */ + ++ /* We are sarting, so we still have not passed through our entrypoint. */ ++ linux_passed_by_entrypoint_flag = 0; ++ + /* The fork_child mechanism is synchronous and calls target_wait, so + we have to mask the async mode. */ + +@@ -1996,6 +2085,26 @@ linux_handle_extended_wait (struct lwp_info *lp, int status, + return 0; + } + ++ /* Used for 'catch syscall' feature. */ ++ if (WSTOPSIG (status) == TRAP_IS_SYSCALL) ++ { ++ if (catch_syscall_enabled () == 0) ++ ourstatus->kind = TARGET_WAITKIND_IGNORE; ++ else ++ { ++ struct regcache *regcache = get_thread_regcache (lp->ptid); ++ struct gdbarch *gdbarch = get_regcache_arch (regcache); ++ ++ ourstatus->kind = ++ (lp->syscall_state == TARGET_WAITKIND_SYSCALL_ENTRY) ? ++ TARGET_WAITKIND_SYSCALL_RETURN : TARGET_WAITKIND_SYSCALL_ENTRY; ++ lp->syscall_state = ourstatus->kind; ++ ourstatus->value.syscall_number = ++ (int) gdbarch_get_syscall_number (gdbarch, lp->ptid); ++ } ++ return 0; ++ } ++ + internal_error (__FILE__, __LINE__, + _("unknown ptrace event %d"), event); + } +@@ -2606,11 +2715,16 @@ linux_nat_filter_event (int lwpid, int status, int options) + } + + /* Save the trap's siginfo in case we need it later. */ +- if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP) ++ if (WIFSTOPPED (status) ++ && (WSTOPSIG (status) == SIGTRAP || WSTOPSIG (status) == TRAP_IS_SYSCALL)) + save_siginfo (lp); + +- /* Handle GNU/Linux's extended waitstatus for trace events. */ +- if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP && status >> 16 != 0) ++ /* Handle GNU/Linux's extended waitstatus for trace events. ++ It is necessary to check if WSTOPSIG is signaling a that ++ the inferior is entering/exiting a system call. */ ++ if (WIFSTOPPED (status) ++ && ((WSTOPSIG (status) == TRAP_IS_SYSCALL) ++ || (WSTOPSIG (status) == SIGTRAP && status >> 16 != 0))) + { + if (debug_linux_nat) + fprintf_unfiltered (gdb_stdlog, +@@ -4262,12 +4376,14 @@ linux_target_install_ops (struct target_ops *t) + t->to_insert_fork_catchpoint = linux_child_insert_fork_catchpoint; + t->to_insert_vfork_catchpoint = linux_child_insert_vfork_catchpoint; + t->to_insert_exec_catchpoint = linux_child_insert_exec_catchpoint; ++ t->to_set_syscall_catchpoint = linux_child_set_syscall_catchpoint; + t->to_pid_to_exec_file = linux_child_pid_to_exec_file; + t->to_post_startup_inferior = linux_child_post_startup_inferior; + t->to_post_attach = linux_child_post_attach; + t->to_follow_fork = linux_child_follow_fork; + t->to_find_memory_regions = linux_nat_find_memory_regions; + t->to_make_corefile_notes = linux_nat_make_corefile_notes; ++ t->to_passed_by_entrypoint = linux_passed_by_entrypoint; + + super_xfer_partial = t->to_xfer_partial; + t->to_xfer_partial = linux_xfer_partial; +diff --git a/gdb/linux-nat.h b/gdb/linux-nat.h +index fec5139..36d2439 100644 +--- a/gdb/linux-nat.h ++++ b/gdb/linux-nat.h +@@ -70,6 +70,13 @@ struct lwp_info + or to a local variable in lin_lwp_wait. */ + struct target_waitstatus waitstatus; + ++ /* Signal wether we are in a SYSCALL_ENTRY or ++ in a SYSCALL_RETURN event. ++ Values: ++ - TARGET_WAITKIND_SYSCALL_ENTRY ++ - TARGET_WAITKIND_SYSCALL_RETURN */ ++ int syscall_state; ++ + /* Next LWP in list. */ + struct lwp_info *next; + }; +diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c +index e18e134..d44b505 100644 +--- a/gdb/linux-tdep.c ++++ b/gdb/linux-tdep.c +@@ -20,6 +20,8 @@ + #include "defs.h" + #include "gdbtypes.h" + #include "linux-tdep.h" ++#include "xml-syscall.h" ++#include "target.h" + + /* This function is suitable for architectures that don't + extend/override the standard siginfo structure. */ +@@ -137,3 +139,81 @@ linux_get_siginfo_type (struct gdbarch *gdbarch) + + return siginfo_type; + } ++ ++/* Structure used to store information about the available syscalls in ++ the system. */ ++static const struct syscalls_info *sysinfo = NULL; ++ ++/* A flag to tell if we already initialized the structure above. */ ++static int have_initialized_sysinfo = 0; ++ ++/* The filename of the syscall's XML. */ ++static const char *xml_syscall_file = NULL; ++ ++/* Initializes the syscalls_info structure according to the ++ architecture. */ ++static void ++init_sysinfo (struct gdbarch *gdbarch) ++{ ++ /* Did we already try to initialize the structure? */ ++ if (have_initialized_sysinfo) ++ return; ++ ++ if (xml_syscall_file == NULL) ++ xml_syscall_file = gdbarch_xml_syscall_filename (gdbarch); ++ ++ sysinfo = xml_init_syscalls_info (xml_syscall_file); ++ ++ have_initialized_sysinfo = 1; ++ ++ if (sysinfo == NULL) ++ { ++ if (xml_syscall_file) ++ /* The initialization failed. Let's show a warning ++ message to the user (just this time) and leave. */ ++ warning (_("Could not load the syscall XML file '%s'.\n\ ++GDB will not be able to display syscall names."), xml_syscall_file); ++ else ++ /* There's no file to open. Let's warn the user. */ ++ warning (_("There is no XML file to open.\n\ ++GDB will not be able to display syscall names.")); ++ } ++} ++ ++static void ++linux_get_syscall_by_number (struct gdbarch *gdbarch, ++ int syscall_number, ++ struct syscall *s) ++{ ++ init_sysinfo (gdbarch); ++ ++ s->number = syscall_number; ++ s->name = xml_get_syscall_name (sysinfo, syscall_number); ++} ++ ++static void ++linux_get_syscall_by_name (struct gdbarch *gdbarch, ++ const char *syscall_name, ++ struct syscall *s) ++{ ++ init_sysinfo (gdbarch); ++ ++ s->number = xml_get_syscall_number (sysinfo, syscall_name); ++ s->name = syscall_name; ++} ++ ++static const char ** ++linux_get_syscall_names (struct gdbarch *gdbarch) ++{ ++ init_sysinfo (gdbarch); ++ ++ return xml_list_of_syscalls (sysinfo); ++} ++ ++void ++linux_tdep_init (struct gdbarch *gdbarch) ++{ ++ set_gdbarch_get_syscall_by_number (gdbarch, linux_get_syscall_by_number); ++ set_gdbarch_get_syscall_by_name (gdbarch, linux_get_syscall_by_name); ++ set_gdbarch_get_syscall_names (gdbarch, linux_get_syscall_names); ++} +diff --git a/gdb/linux-tdep.h b/gdb/linux-tdep.h +index 50af511..1e1e541 100644 +--- a/gdb/linux-tdep.h ++++ b/gdb/linux-tdep.h +@@ -22,4 +22,6 @@ + + struct type *linux_get_siginfo_type (struct gdbarch *); + ++extern void linux_tdep_init (struct gdbarch *gdbarch); ++ + #endif /* linux-tdep.h */ +diff --git a/gdb/m2-lang.c b/gdb/m2-lang.c +index 9e4bb1b..9ca3ae1 100644 +--- a/gdb/m2-lang.c ++++ b/gdb/m2-lang.c +@@ -29,8 +29,8 @@ + #include "valprint.h" + + extern void _initialize_m2_language (void); +-static void m2_printchar (int, struct ui_file *); +-static void m2_emit_char (int, struct ui_file *, int); ++static void m2_printchar (int, struct type *, struct ui_file *); ++static void m2_emit_char (int, struct type *, struct ui_file *, int); + + /* Print the character C on STREAM as part of the contents of a literal + string whose delimiter is QUOTER. Note that that format for printing +@@ -39,7 +39,7 @@ static void m2_emit_char (int, struct ui_file *, int); + be replaced with a true Modula version. */ + + static void +-m2_emit_char (int c, struct ui_file *stream, int quoter) ++m2_emit_char (int c, struct type *type, struct ui_file *stream, int quoter) + { + + c &= 0xFF; /* Avoid sign bit follies */ +@@ -88,10 +88,10 @@ m2_emit_char (int c, struct ui_file *stream, int quoter) + be replaced with a true Modula version. */ + + static void +-m2_printchar (int c, struct ui_file *stream) ++m2_printchar (int c, struct type *type, struct ui_file *stream) + { + fputs_filtered ("'", stream); +- LA_EMIT_CHAR (c, stream, '\''); ++ LA_EMIT_CHAR (c, type, stream, '\''); + fputs_filtered ("'", stream); + } + +@@ -103,14 +103,15 @@ m2_printchar (int c, struct ui_file *stream) + be replaced with a true Modula version. */ + + static void +-m2_printstr (struct ui_file *stream, const gdb_byte *string, +- unsigned int length, int width, int force_ellipses, ++m2_printstr (struct ui_file *stream, struct type *type, const gdb_byte *string, ++ unsigned int length, int force_ellipses, + const struct value_print_options *options) + { + unsigned int i; + unsigned int things_printed = 0; + int in_quotes = 0; + int need_comma = 0; ++ int width = TYPE_LENGTH (type); + + if (length == 0) + { +@@ -152,7 +153,7 @@ m2_printstr (struct ui_file *stream, const gdb_byte *string, + fputs_filtered ("\", ", stream); + in_quotes = 0; + } +- m2_printchar (string[i], stream); ++ m2_printchar (string[i], type, stream); + fprintf_filtered (stream, " ", reps); + i = rep1 - 1; + things_printed += options->repeat_count_threshold; +@@ -168,7 +169,7 @@ m2_printstr (struct ui_file *stream, const gdb_byte *string, + fputs_filtered ("\"", stream); + in_quotes = 1; + } +- LA_EMIT_CHAR (string[i], stream, '"'); ++ LA_EMIT_CHAR (string[i], type, stream, '"'); + ++things_printed; + } + } +diff --git a/gdb/m2-valprint.c b/gdb/m2-valprint.c +index 71c410c..41fb8fe 100644 +--- a/gdb/m2-valprint.c ++++ b/gdb/m2-valprint.c +@@ -237,7 +237,8 @@ print_unpacked_pointer (struct type *type, + && TYPE_CODE (elttype) == TYPE_CODE_INT + && (options->format == 0 || options->format == 's') + && addr != 0) +- return val_print_string (addr, -1, TYPE_LENGTH (elttype), stream, options); ++ return val_print_string (TYPE_TARGET_TYPE (type), addr, -1, ++ stream, options); + + return 0; + } +@@ -294,7 +295,7 @@ m2_print_array_contents (struct type *type, const gdb_byte *valaddr, + || ((current_language->la_language == language_m2) + && (TYPE_CODE (type) == TYPE_CODE_CHAR))) + && (options->format == 0 || options->format == 's')) +- val_print_string (address, len+1, eltlen, stream, options); ++ val_print_string (type, address, len+1, stream, options); + else + { + fprintf_filtered (stream, "{"); +@@ -359,7 +360,8 @@ m2_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, + len = temp_len; + } + +- LA_PRINT_STRING (stream, valaddr + embedded_offset, len, 1, 0, ++ LA_PRINT_STRING (stream, TYPE_TARGET_TYPE (type), ++ valaddr + embedded_offset, len, 0, + options); + i = len; + } +@@ -547,7 +549,7 @@ m2_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, + else + fprintf_filtered (stream, "%d", (int) val); + fputs_filtered (" ", stream); +- LA_PRINT_CHAR ((unsigned char) val, stream); ++ LA_PRINT_CHAR ((unsigned char) val, type, stream); + } + break; + +diff --git a/gdb/m32r-tdep.c b/gdb/m32r-tdep.c +index 5f4b9a6..eccfe31 100644 +--- a/gdb/m32r-tdep.c ++++ b/gdb/m32r-tdep.c +@@ -713,7 +713,7 @@ m32r_push_dummy_call (struct gdbarch *gdbarch, struct value *function, + if (len > 8 + && (typecode == TYPE_CODE_STRUCT || typecode == TYPE_CODE_UNION)) + { +- store_unsigned_integer (valbuf, 4, VALUE_ADDRESS (args[argnum])); ++ store_unsigned_integer (valbuf, 4, value_address (args[argnum])); + typecode = TYPE_CODE_PTR; + len = 4; + val = valbuf; +diff --git a/gdb/macroexp.c b/gdb/macroexp.c +index f0a8c1f..752a939 100644 +--- a/gdb/macroexp.c ++++ b/gdb/macroexp.c +@@ -23,6 +23,7 @@ + #include "macrotab.h" + #include "macroexp.h" + #include "gdb_assert.h" ++#include "c-lang.h" + + + +@@ -320,14 +321,17 @@ get_character_constant (struct macro_buffer *tok, char *p, char *end) + way GDB's C/C++ lexer does. So we call parse_escape in utils.c + to handle escape sequences. */ + if ((p + 1 <= end && *p == '\'') +- || (p + 2 <= end && p[0] == 'L' && p[1] == '\'')) ++ || (p + 2 <= end ++ && (p[0] == 'L' || p[0] == 'u' || p[0] == 'U') ++ && p[1] == '\'')) + { + char *tok_start = p; + char *body_start; ++ int char_count = 0; + + if (*p == '\'') + p++; +- else if (*p == 'L') ++ else if (*p == 'L' || *p == 'u' || *p == 'U') + p += 2; + else + gdb_assert (0); +@@ -339,7 +343,7 @@ get_character_constant (struct macro_buffer *tok, char *p, char *end) + error (_("Unmatched single quote.")); + else if (*p == '\'') + { +- if (p == body_start) ++ if (!char_count) + error (_("A character constant must contain at least one " + "character.")); + p++; +@@ -348,10 +352,13 @@ get_character_constant (struct macro_buffer *tok, char *p, char *end) + else if (*p == '\\') + { + p++; +- parse_escape (&p); ++ char_count += c_parse_escape (&p, NULL); + } + else +- p++; ++ { ++ p++; ++ char_count++; ++ } + } + + set_token (tok, tok_start, p); +@@ -370,16 +377,16 @@ static int + get_string_literal (struct macro_buffer *tok, char *p, char *end) + { + if ((p + 1 <= end +- && *p == '\"') ++ && *p == '"') + || (p + 2 <= end +- && p[0] == 'L' +- && p[1] == '\"')) ++ && (p[0] == 'L' || p[0] == 'u' || p[0] == 'U') ++ && p[1] == '"')) + { + char *tok_start = p; + +- if (*p == '\"') ++ if (*p == '"') + p++; +- else if (*p == 'L') ++ else if (*p == 'L' || *p == 'u' || *p == 'U') + p += 2; + else + gdb_assert (0); +@@ -388,7 +395,7 @@ get_string_literal (struct macro_buffer *tok, char *p, char *end) + { + if (p >= end) + error (_("Unterminated string in expression.")); +- else if (*p == '\"') ++ else if (*p == '"') + { + p++; + break; +@@ -399,7 +406,7 @@ get_string_literal (struct macro_buffer *tok, char *p, char *end) + else if (*p == '\\') + { + p++; +- parse_escape (&p); ++ c_parse_escape (&p, NULL); + } + else + p++; +diff --git a/gdb/main.c b/gdb/main.c +index 5d4640b..6f9e61b 100644 +--- a/gdb/main.c ++++ b/gdb/main.c +@@ -40,6 +40,8 @@ + #include "interps.h" + #include "main.h" + ++#include "python/python.h" ++ + /* If nonzero, display time usage both at startup and for each command. */ + + int display_time; +@@ -62,6 +64,9 @@ int dbx_commands = 0; + /* System root path, used to find libraries etc. */ + char *gdb_sysroot = 0; + ++/* GDB datadir, used to store data files. */ ++char *gdb_datadir = 0; ++ + struct ui_file *gdb_stdout; + struct ui_file *gdb_stderr; + struct ui_file *gdb_stdlog; +@@ -211,6 +216,8 @@ captured_main (void *data) + char *cdarg = NULL; + char *ttyarg = NULL; + ++ int python_script = 0; ++ + /* These are static so that we can take their address in an initializer. */ + static int print_help; + static int print_version; +@@ -357,6 +364,40 @@ captured_main (void *data) + } + } + ++#ifdef GDB_DATADIR_RELOCATABLE ++ gdb_datadir = make_relative_prefix (argv[0], BINDIR, GDB_DATADIR); ++ if (gdb_datadir) ++ { ++ struct stat s; ++ int res = 0; ++ ++ if (stat (gdb_datadir, &s) == 0) ++ if (S_ISDIR (s.st_mode)) ++ res = 1; ++ ++ if (res == 0) ++ { ++ xfree (gdb_datadir); ++ gdb_datadir = xstrdup (GDB_DATADIR); ++ } ++ } ++ else ++ gdb_datadir = xstrdup (GDB_DATADIR); ++#else ++ gdb_datadir = xstrdup (GDB_DATADIR); ++#endif /* GDB_DATADIR_RELOCATABLE */ ++ ++ /* Canonicalize the GDB's datadir path. */ ++ if (*gdb_datadir) ++ { ++ char *canon_debug = lrealpath (gdb_datadir); ++ if (canon_debug) ++ { ++ xfree (gdb_datadir); ++ gdb_datadir = canon_debug; ++ } ++ } ++ + get_init_files (&system_gdbinit, &home_gdbinit, &local_gdbinit); + + /* There will always be an interpreter. Either the one passed into +@@ -441,10 +482,14 @@ captured_main (void *data) + {"args", no_argument, &set_args, 1}, + {"l", required_argument, 0, 'l'}, + {"return-child-result", no_argument, &return_child_result, 1}, ++#if HAVE_PYTHON ++ {"python", no_argument, 0, 'P'}, ++ {"P", no_argument, 0, 'P'}, ++#endif + {0, no_argument, 0, 0} + }; + +- while (1) ++ while (!python_script) + { + int option_index; + +@@ -462,6 +507,9 @@ captured_main (void *data) + case 0: + /* Long option that just sets a flag. */ + break; ++ case 'P': ++ python_script = 1; ++ break; + case OPT_SE: + symarg = optarg; + execarg = optarg; +@@ -638,7 +686,31 @@ extern int gdbtk_test (char *); + use_windows = 0; + } + +- if (set_args) ++ if (python_script) ++ { ++ /* The first argument is a python script to evaluate, and ++ subsequent arguments are passed to the script for ++ processing there. */ ++ if (optind >= argc) ++ { ++ fprintf_unfiltered (gdb_stderr, ++ _("%s: Python script file name required\n"), ++ argv[0]); ++ exit (1); ++ } ++ ++ /* FIXME: should handle inferior I/O intelligently here. ++ E.g., should be possible to run gdb in pipeline and have ++ Python (and gdb) output go to stderr or file; and if a ++ prompt is needed, open the tty. */ ++ quiet = 1; ++ /* FIXME: should read .gdbinit if, and only if, a prompt is ++ requested by the script. Though... maybe this is not ++ ideal? */ ++ /* FIXME: likewise, reading in history. */ ++ inhibit_gdbinit = 1; ++ } ++ else if (set_args) + { + /* The remaining options are the command-line options for the + inferior. The first one is the sym/exec file, and the rest +@@ -866,7 +938,8 @@ Can't attach to process and specify a core file at the same time.")); + xfree (cmdarg); + + /* Read in the old history after all the command files have been read. */ +- init_history (); ++ if (!python_script) ++ init_history (); + + if (batch) + { +@@ -895,13 +968,25 @@ Can't attach to process and specify a core file at the same time.")); + #endif + } + +- /* NOTE: cagney/1999-11-07: There is probably no reason for not +- moving this loop and the code found in captured_command_loop() +- into the command_loop() proper. The main thing holding back that +- change - SET_TOP_LEVEL() - has been eliminated. */ +- while (1) ++#if HAVE_PYTHON ++ if (python_script) + { +- catch_errors (captured_command_loop, 0, "", RETURN_MASK_ALL); ++ extern int pagination_enabled; ++ pagination_enabled = 0; ++ run_python_script (argc - optind, &argv[optind]); ++ return 1; ++ } ++ else ++#endif ++ { ++ /* NOTE: cagney/1999-11-07: There is probably no reason for not ++ moving this loop and the code found in captured_command_loop() ++ into the command_loop() proper. The main thing holding back that ++ change - SET_TOP_LEVEL() - has been eliminated. */ ++ while (1) ++ { ++ catch_errors (captured_command_loop, 0, "", RETURN_MASK_ALL); ++ } + } + /* No exit -- exit is through quit_command. */ + } +@@ -933,7 +1018,12 @@ print_gdb_help (struct ui_file *stream) + fputs_unfiltered (_("\ + This is the GNU debugger. Usage:\n\n\ + gdb [options] [executable-file [core-file or process-id]]\n\ +- gdb [options] --args executable-file [inferior-arguments ...]\n\n\ ++ gdb [options] --args executable-file [inferior-arguments ...]\n"), stream); ++#if HAVE_PYTHON ++ fputs_unfiltered (_("\ ++ gdb [options] [--python|-P] script-file [script-arguments ...]\n"), stream); ++#endif ++ fputs_unfiltered (_("\n\ + Options:\n\n\ + "), stream); + fputs_unfiltered (_("\ +@@ -971,7 +1061,13 @@ Options:\n\n\ + --nw Do not use a window interface.\n\ + --nx Do not read "), stream); + fputs_unfiltered (gdbinit, stream); +- fputs_unfiltered (_(" file.\n\ ++ fputs_unfiltered (_(" file.\n"), stream); ++#if HAVE_PYTHON ++ fputs_unfiltered (_("\ ++ --python, -P Following argument is Python script file; remaining\n\ ++ arguments are passed to script.\n"), stream); ++#endif ++ fputs_unfiltered (_("\ + --quiet Do not print version number on startup.\n\ + --readnow Fully read symbol files on first access.\n\ + "), stream); +diff --git a/gdb/maint.c b/gdb/maint.c +index 56cafe9..1b57ff5 100644 +--- a/gdb/maint.c ++++ b/gdb/maint.c +@@ -906,4 +906,12 @@ When enabled GDB is profiled."), + show_maintenance_profile_p, + &maintenance_set_cmdlist, + &maintenance_show_cmdlist); ++ add_setshow_filename_cmd ("gdb_datadir", class_maintenance, ++ &gdb_datadir, _("Set GDB's datadir path."), ++ _("Show GDB's datadir path."), ++ _("\ ++When set, GDB uses the specified path to search for data files."), ++ NULL, NULL, ++ &maintenance_set_cmdlist, ++ &maintenance_show_cmdlist); + } +diff --git a/gdb/mdebugread.c b/gdb/mdebugread.c +index 7cbcc59..e507c3b 100644 +--- a/gdb/mdebugread.c ++++ b/gdb/mdebugread.c +@@ -4696,7 +4696,7 @@ new_type (char *name) + { + struct type *t; + +- t = alloc_type (current_objfile); ++ t = alloc_type (current_objfile, NULL); + TYPE_NAME (t) = name; + TYPE_CPLUS_SPECIFIC (t) = (struct cplus_struct_type *) &cplus_struct_default; + return t; +diff --git a/gdb/mi/mi-cmd-var.c b/gdb/mi/mi-cmd-var.c +index 143074b..0f4efba 100644 +--- a/gdb/mi/mi-cmd-var.c ++++ b/gdb/mi/mi-cmd-var.c +@@ -249,6 +249,41 @@ mi_cmd_var_set_format (char *command, char **argv, int argc) + } + + void ++mi_cmd_var_set_visualizer (char *command, char **argv, int argc) ++{ ++ struct varobj *var; ++ ++ if (argc != 2) ++ error ("Usage: NAME VISUALIZER_FUNCTION."); ++ ++ var = varobj_get_handle (argv[0]); ++ ++ if (var == NULL) ++ error ("Variable object not found"); ++ ++ varobj_set_visualizer (var, argv[1]); ++} ++ ++void ++mi_cmd_var_set_child_range (char *command, char **argv, int argc) ++{ ++ struct varobj *var; ++ int from, to; ++ ++ if (argc != 3) ++ error (_("-var-set-child-range: NAME FROM TO")); ++ ++ var = varobj_get_handle (argv[0]); ++ if (var == NULL) ++ error (_("Variable object not found")); ++ ++ from = atoi (argv[1]); ++ to = atoi (argv[2]); ++ ++ varobj_set_child_range (var, from, to); ++} ++ ++void + mi_cmd_var_set_frozen (char *command, char **argv, int argc) + { + struct varobj *var; +@@ -369,6 +404,8 @@ mi_cmd_var_list_children (char *command, char **argv, int argc) + int numchild; + enum print_values print_values; + int ix; ++ int from, to; ++ char *display_hint; + + if (argc != 1 && argc != 2) + error (_("mi_cmd_var_list_children: Usage: [PRINT_VALUES] NAME")); +@@ -388,14 +425,22 @@ mi_cmd_var_list_children (char *command, char **argv, int argc) + else + print_values = PRINT_NO_VALUES; + +- if (VEC_length (varobj_p, children) == 0) ++ varobj_get_child_range (var, children, &from, &to); ++ if (from >= to) + return; + ++ display_hint = varobj_get_display_hint (var); ++ if (display_hint) ++ { ++ ui_out_field_string (uiout, "displayhint", display_hint); ++ xfree (display_hint); ++ } ++ + if (mi_version (uiout) == 1) + cleanup_children = make_cleanup_ui_out_tuple_begin_end (uiout, "children"); + else + cleanup_children = make_cleanup_ui_out_list_begin_end (uiout, "children"); +- for (ix = 0; VEC_iterate (varobj_p, children, ix, child); ++ix) ++ for (ix = from; ix < to && VEC_iterate (varobj_p, children, ix, child); ++ix) + { + struct cleanup *cleanup_child; + cleanup_child = make_cleanup_ui_out_tuple_begin_end (uiout, "child"); +@@ -662,6 +707,8 @@ varobj_update_one (struct varobj *var, enum print_values print_values, + + for (i = 0; VEC_iterate (varobj_update_result, changes, i, r); ++i) + { ++ char *display_hint; ++ + if (mi_version (uiout) > 1) + cleanup = make_cleanup_ui_out_tuple_begin_end (uiout, NULL); + ui_out_field_string (uiout, "name", varobj_get_objname (r->varobj)); +@@ -695,6 +742,36 @@ varobj_update_one (struct varobj *var, enum print_values print_values, + ui_out_field_int (uiout, "new_num_children", + varobj_get_num_children (r->varobj)); + } ++ ++ display_hint = varobj_get_display_hint (var); ++ if (display_hint) ++ { ++ ui_out_field_string (uiout, "displayhint", display_hint); ++ xfree (display_hint); ++ } ++ ++ if (r->children_changed) ++ { ++ int ix, from, to; ++ struct varobj *child; ++ struct cleanup *cleanup = ++ make_cleanup_ui_out_list_begin_end (uiout, "children"); ++ ++ VEC (varobj_p)* children = varobj_list_children (r->varobj); ++ varobj_get_child_range (r->varobj, children, &from, &to); ++ ++ for (ix = from; ++ ix < to && VEC_iterate (varobj_p, children, ix, child); ++ ++ix) ++ { ++ struct cleanup *cleanup_child; ++ cleanup_child = make_cleanup_ui_out_tuple_begin_end (uiout, NULL); ++ print_varobj (child, print_values, 1 /* print expression */); ++ do_cleanups (cleanup_child); ++ } ++ ++ do_cleanups (cleanup); ++ } + + if (mi_version (uiout) > 1) + do_cleanups (cleanup); +diff --git a/gdb/mi/mi-cmds.c b/gdb/mi/mi-cmds.c +index 2610b6a..f31233b 100644 +--- a/gdb/mi/mi-cmds.c ++++ b/gdb/mi/mi-cmds.c +@@ -160,7 +160,9 @@ struct mi_cmd mi_cmds[] = + { "var-info-num-children", { NULL, 0 }, mi_cmd_var_info_num_children}, + { "var-info-type", { NULL, 0 }, mi_cmd_var_info_type}, + { "var-list-children", { NULL, 0 }, mi_cmd_var_list_children}, ++ { "var-set-child-range", { NULL, 0 }, mi_cmd_var_set_child_range }, + { "var-set-format", { NULL, 0 }, mi_cmd_var_set_format}, ++ { "var-set-visualizer", { NULL, 0 }, mi_cmd_var_set_visualizer}, + { "var-set-frozen", { NULL, 0 }, mi_cmd_var_set_frozen}, + { "var-show-attributes", { NULL, 0 }, mi_cmd_var_show_attributes}, + { "var-show-format", { NULL, 0 }, mi_cmd_var_show_format}, +diff --git a/gdb/mi/mi-cmds.h b/gdb/mi/mi-cmds.h +index 39f16fb..291a07f 100644 +--- a/gdb/mi/mi-cmds.h ++++ b/gdb/mi/mi-cmds.h +@@ -92,7 +92,9 @@ extern mi_cmd_argv_ftype mi_cmd_var_info_num_children; + extern mi_cmd_argv_ftype mi_cmd_var_info_type; + extern mi_cmd_argv_ftype mi_cmd_var_list_children; + extern mi_cmd_argv_ftype mi_cmd_var_set_format; ++extern mi_cmd_argv_ftype mi_cmd_var_set_child_range; + extern mi_cmd_argv_ftype mi_cmd_var_set_frozen; ++extern mi_cmd_argv_ftype mi_cmd_var_set_visualizer; + extern mi_cmd_argv_ftype mi_cmd_var_show_attributes; + extern mi_cmd_argv_ftype mi_cmd_var_show_format; + extern mi_cmd_argv_ftype mi_cmd_var_update; +diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c +index b905a9e..eaa5f12 100644 +--- a/gdb/mi/mi-main.c ++++ b/gdb/mi/mi-main.c +@@ -777,7 +777,7 @@ mi_cmd_data_evaluate_expression (char *command, char **argv, int argc) + get_user_print_options (&opts); + opts.deref_ref = 0; + val_print (value_type (val), value_contents (val), +- value_embedded_offset (val), VALUE_ADDRESS (val), ++ value_embedded_offset (val), value_address (val), + stb->stream, 0, &opts, current_language); + + ui_out_field_stream (uiout, "value", stb); +@@ -1101,6 +1101,10 @@ mi_cmd_list_features (char *command, char **argv, int argc) + ui_out_field_string (uiout, NULL, "frozen-varobjs"); + ui_out_field_string (uiout, NULL, "pending-breakpoints"); + ui_out_field_string (uiout, NULL, "thread-info"); ++ ++#if HAVE_PYTHON ++ ui_out_field_string (uiout, NULL, "python"); ++#endif + + do_cleanups (cleanup); + return; +@@ -1317,6 +1321,7 @@ mi_cmd_execute (struct mi_parse *parse) + struct cleanup *cleanup; + int i; + free_all_values (); ++ free_all_types (); + + current_token = xstrdup (parse->token); + cleanup = make_cleanup (free_current_contents, ¤t_token); +diff --git a/gdb/minsyms.c b/gdb/minsyms.c +index bf776b3..e4b0f31 100644 +--- a/gdb/minsyms.c ++++ b/gdb/minsyms.c +@@ -48,6 +48,8 @@ + #include "value.h" + #include "cp-abi.h" + #include "target.h" ++#include "cp-support.h" ++#include "language.h" + + /* Accumulate the minimal symbols for each objfile in bunches of BUNCH_SIZE. + At the end, copy them all into one newly allocated location on an objfile's +@@ -187,6 +189,9 @@ lookup_minimal_symbol (const char *name, const char *sfile, + unsigned int hash = msymbol_hash (name) % MINIMAL_SYMBOL_HASH_SIZE; + unsigned int dem_hash = msymbol_hash_iw (name) % MINIMAL_SYMBOL_HASH_SIZE; + ++ int needtofreename = 0; ++ const char *modified_name; ++ + if (sfile != NULL) + { + char *p = strrchr (sfile, '/'); +@@ -194,6 +199,18 @@ lookup_minimal_symbol (const char *name, const char *sfile, + sfile = p + 1; + } + ++ /* For C++, canonicalize the input name. */ ++ modified_name = name; ++ if (current_language->la_language == language_cplus) ++ { ++ char *cname = cp_canonicalize_string (name); ++ if (cname) ++ { ++ modified_name = cname; ++ needtofreename = 1; ++ } ++ } ++ + for (objfile = object_files; + objfile != NULL && found_symbol == NULL; + objfile = objfile->next) +@@ -218,9 +235,16 @@ lookup_minimal_symbol (const char *name, const char *sfile, + int match; + + if (pass == 1) +- match = strcmp (SYMBOL_LINKAGE_NAME (msymbol), name) == 0; ++ { ++ match = strcmp (SYMBOL_LINKAGE_NAME (msymbol), ++ modified_name) == 0; ++ } + else +- match = SYMBOL_MATCHES_SEARCH_NAME (msymbol, name); ++ { ++ match = SYMBOL_MATCHES_SEARCH_NAME (msymbol, ++ modified_name); ++ } ++ + if (match) + { + switch (MSYMBOL_TYPE (msymbol)) +@@ -259,6 +283,10 @@ lookup_minimal_symbol (const char *name, const char *sfile, + } + } + } ++ ++ if (needtofreename) ++ xfree ((void *) modified_name); ++ + /* External symbols are best. */ + if (found_symbol) + return found_symbol; +diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c +index 6c8c4c0..7d283a4 100644 +--- a/gdb/mips-tdep.c ++++ b/gdb/mips-tdep.c +@@ -2757,7 +2757,7 @@ mips_eabi_push_dummy_call (struct gdbarch *gdbarch, struct value *function, + if (len > regsize + && (typecode == TYPE_CODE_STRUCT || typecode == TYPE_CODE_UNION)) + { +- store_unsigned_integer (valbuf, regsize, VALUE_ADDRESS (arg)); ++ store_unsigned_integer (valbuf, regsize, value_address (arg)); + typecode = TYPE_CODE_PTR; + len = regsize; + val = valbuf; +diff --git a/gdb/mipsread.c b/gdb/mipsread.c +index a84003f..924c1c5 100644 +--- a/gdb/mipsread.c ++++ b/gdb/mipsread.c +@@ -394,6 +394,7 @@ static struct sym_fns ecoff_sym_fns = + mipscoff_new_init, /* sym_new_init: init anything gbl to entire symtab */ + mipscoff_symfile_init, /* sym_init: read initial info, setup for sym_read() */ + mipscoff_symfile_read, /* sym_read: read a symbol file into symtab */ ++ NULL, /* sym_read_psymbols */ + mipscoff_symfile_finish, /* sym_finish: finished with file, cleanup */ + default_symfile_offsets, /* sym_offsets: dummy FIXME til implem sym reloc */ + default_symfile_segments, /* sym_segments: Get segment information from +diff --git a/gdb/mn10300-tdep.c b/gdb/mn10300-tdep.c +index f0cea27..02be43a 100644 +--- a/gdb/mn10300-tdep.c ++++ b/gdb/mn10300-tdep.c +@@ -1027,7 +1027,7 @@ mn10300_push_dummy_call (struct gdbarch *gdbarch, + /* Change to pointer-to-type. */ + arg_len = push_size; + store_unsigned_integer (valbuf, push_size, +- VALUE_ADDRESS (*args)); ++ value_address (*args)); + val = &valbuf[0]; + } + else +diff --git a/gdb/objc-lang.c b/gdb/objc-lang.c +index a6c74a3..9b8d801 100644 +--- a/gdb/objc-lang.c ++++ b/gdb/objc-lang.c +@@ -280,7 +280,7 @@ objc_demangle (const char *mangled, int options) + for printing characters and strings is language specific. */ + + static void +-objc_emit_char (int c, struct ui_file *stream, int quoter) ++objc_emit_char (int c, struct type *type, struct ui_file *stream, int quoter) + { + + c &= 0xFF; /* Avoid sign bit follies. */ +@@ -326,10 +326,10 @@ objc_emit_char (int c, struct ui_file *stream, int quoter) + } + + static void +-objc_printchar (int c, struct ui_file *stream) ++objc_printchar (int c, struct type *type, struct ui_file *stream) + { + fputs_filtered ("'", stream); +- objc_emit_char (c, stream, '\''); ++ objc_emit_char (c, type, stream, '\''); + fputs_filtered ("'", stream); + } + +@@ -340,14 +340,16 @@ objc_printchar (int c, struct ui_file *stream) + FORCE_ELLIPSES. */ + + static void +-objc_printstr (struct ui_file *stream, const gdb_byte *string, +- unsigned int length, int width, int force_ellipses, ++objc_printstr (struct ui_file *stream, struct type *type, ++ const gdb_byte *string, unsigned int length, ++ int force_ellipses, + const struct value_print_options *options) + { + unsigned int i; + unsigned int things_printed = 0; + int in_quotes = 0; + int need_comma = 0; ++ int width = TYPE_LENGTH (type); + + /* If the string was not truncated due to `set print elements', and + the last byte of it is a null, we don't print that, in +@@ -395,7 +397,7 @@ objc_printstr (struct ui_file *stream, const gdb_byte *string, + fputs_filtered ("\", ", stream); + in_quotes = 0; + } +- objc_printchar (string[i], stream); ++ objc_printchar (string[i], type, stream); + fprintf_filtered (stream, " ", reps); + i = rep1 - 1; + things_printed += options->repeat_count_threshold; +@@ -411,7 +413,7 @@ objc_printstr (struct ui_file *stream, const gdb_byte *string, + fputs_filtered ("\"", stream); + in_quotes = 1; + } +- objc_emit_char (string[i], stream, '"'); ++ objc_emit_char (string[i], type, stream, '"'); + ++things_printed; + } + } +diff --git a/gdb/objfiles.c b/gdb/objfiles.c +index bc77de8..079ebcf 100644 +--- a/gdb/objfiles.c ++++ b/gdb/objfiles.c +@@ -691,6 +691,20 @@ have_partial_symbols (void) + return 1; + } + } ++ ++ /* Try again, after reading partial symbols. We do this in two ++ passes because objfiles are always added to the head of the list, ++ and there might be a later objfile for which we've already read ++ partial symbols. */ ++ ALL_OBJFILES (ofp) ++ { ++ require_partial_symbols (ofp); ++ if (ofp->psymtabs != NULL) ++ { ++ return 1; ++ } ++ } ++ + return 0; + } + +diff --git a/gdb/objfiles.h b/gdb/objfiles.h +index 60d3143..b6fdd92 100644 +--- a/gdb/objfiles.h ++++ b/gdb/objfiles.h +@@ -212,6 +212,11 @@ struct objfile + + struct partial_symtab *psymtabs; + ++ /* An address map that can be used to quickly determine if an ++ address comes from this objfile. This can be NULL. */ ++ ++ struct addrmap *quick_addrmap; ++ + /* Map addresses to the entries of PSYMTABS. It would be more efficient to + have a map per the whole process but ADDRMAP cannot selectively remove + its items during FREE_OBJFILE. This mapping is already present even for +@@ -420,6 +425,15 @@ struct objfile + #define OBJF_KEEPBFD (1 << 4) /* Do not delete bfd */ + + ++/* Set if we have tried to read partial symtabs for this objfile. ++ This is used to allow lazy reading of partial symtabs. */ ++ ++#define OBJF_SYMTABS_READ (1 << 6) ++ ++/* This flag is set for the main objfile. */ ++ ++#define OBJF_MAIN (1 << 7) ++ + /* The object file that the main symbol table was loaded from (e.g. the + argument to the "symbol-file" or "file" command). */ + +@@ -556,6 +570,13 @@ extern void *objfile_data (struct objfile *objfile, + ALL_OBJFILES (objfile) \ + ALL_OBJFILE_PSYMTABS (objfile, p) + ++/* Like ALL_PSYMTABS, but ensure that partial symbols have been read ++ before examining the objfile. */ ++ ++#define ALL_PSYMTABS_REQUIRED(objfile, p) \ ++ ALL_OBJFILES (objfile) \ ++ ALL_OBJFILE_PSYMTABS (require_partial_symbols (objfile), p) ++ + /* Traverse all minimal symbols in all objfiles. */ + + #define ALL_MSYMBOLS(objfile, m) \ +diff --git a/gdb/p-lang.c b/gdb/p-lang.c +index 41da3e0..e743a6f 100644 +--- a/gdb/p-lang.c ++++ b/gdb/p-lang.c +@@ -97,7 +97,8 @@ pascal_main_name (void) + but this does not happen for Free Pascal nor for GPC. */ + int + is_pascal_string_type (struct type *type,int *length_pos, +- int *length_size, int *string_pos, int *char_size, ++ int *length_size, int *string_pos, ++ struct type **char_type, + char **arrayname) + { + if (TYPE_CODE (type) == TYPE_CODE_STRUCT) +@@ -114,8 +115,8 @@ is_pascal_string_type (struct type *type,int *length_pos, + *length_size = TYPE_LENGTH (TYPE_FIELD_TYPE (type, 0)); + if (string_pos) + *string_pos = TYPE_FIELD_BITPOS (type, 1) / TARGET_CHAR_BIT; +- if (char_size) +- *char_size = 1; ++ if (char_type) ++ *char_type = TYPE_TARGET_TYPE (TYPE_FIELD_TYPE (type, 1)); + if (arrayname) + *arrayname = TYPE_FIELDS (type)[1].name; + return 2; +@@ -126,7 +127,6 @@ is_pascal_string_type (struct type *type,int *length_pos, + && strcmp (TYPE_FIELDS (type)[0].name, "Capacity") == 0 + && strcmp (TYPE_FIELDS (type)[1].name, "length") == 0) + { +- struct type *char_type; + if (length_pos) + *length_pos = TYPE_FIELD_BITPOS (type, 1) / TARGET_CHAR_BIT; + if (length_size) +@@ -134,13 +134,12 @@ is_pascal_string_type (struct type *type,int *length_pos, + if (string_pos) + *string_pos = TYPE_FIELD_BITPOS (type, 2) / TARGET_CHAR_BIT; + /* FIXME: how can I detect wide chars in GPC ?? */ +- char_type = TYPE_FIELD_TYPE (type,2); +- if (char_size && TYPE_CODE (char_type) == TYPE_CODE_ARRAY) ++ if (char_type) + { +- *char_size = TYPE_LENGTH (TYPE_TARGET_TYPE (char_type)); ++ *char_type = TYPE_TARGET_TYPE (TYPE_FIELD_TYPE (type, 2)); ++ if (TYPE_CODE (*char_type) == TYPE_CODE_ARRAY) ++ *char_type = TYPE_TARGET_TYPE (*char_type); + } +- else if (char_size) +- *char_size = 1; + if (arrayname) + *arrayname = TYPE_FIELDS (type)[2].name; + return 3; +@@ -182,14 +181,15 @@ pascal_one_char (int c, struct ui_file *stream, int *in_quotes) + } + } + +-static void pascal_emit_char (int c, struct ui_file *stream, int quoter); ++static void pascal_emit_char (int c, struct type *type, ++ struct ui_file *stream, int quoter); + + /* Print the character C on STREAM as part of the contents of a literal + string whose delimiter is QUOTER. Note that that format for printing + characters and strings is language specific. */ + + static void +-pascal_emit_char (int c, struct ui_file *stream, int quoter) ++pascal_emit_char (int c, struct type *type, struct ui_file *stream, int quoter) + { + int in_quotes = 0; + pascal_one_char (c, stream, &in_quotes); +@@ -198,7 +198,7 @@ pascal_emit_char (int c, struct ui_file *stream, int quoter) + } + + void +-pascal_printchar (int c, struct ui_file *stream) ++pascal_printchar (int c, struct type *type, struct ui_file *stream) + { + int in_quotes = 0; + pascal_one_char (c, stream, &in_quotes); +@@ -212,14 +212,16 @@ pascal_printchar (int c, struct ui_file *stream) + had to stop before printing LENGTH characters, or if FORCE_ELLIPSES. */ + + void +-pascal_printstr (struct ui_file *stream, const gdb_byte *string, +- unsigned int length, int width, int force_ellipses, ++pascal_printstr (struct ui_file *stream, struct type *type, ++ const gdb_byte *string, unsigned int length, ++ int force_ellipses, + const struct value_print_options *options) + { + unsigned int i; + unsigned int things_printed = 0; + int in_quotes = 0; + int need_comma = 0; ++ int width = TYPE_LENGTH (type); + + /* If the string was not truncated due to `set print elements', and + the last byte of it is a null, we don't print that, in traditional C +@@ -273,7 +275,7 @@ pascal_printstr (struct ui_file *stream, const gdb_byte *string, + fputs_filtered ("', ", stream); + in_quotes = 0; + } +- pascal_printchar (current_char, stream); ++ pascal_printchar (current_char, type, stream); + fprintf_filtered (stream, " ", reps); + i = rep1 - 1; + things_printed += options->repeat_count_threshold; +diff --git a/gdb/p-lang.h b/gdb/p-lang.h +index 09a4569..2b2eb2d 100644 +--- a/gdb/p-lang.h ++++ b/gdb/p-lang.h +@@ -48,12 +48,13 @@ extern void pascal_type_print_method_args (char *, char *, + /* These are in p-lang.c: */ + + extern int +- is_pascal_string_type (struct type *, int *, int *, int *, int *, char **); ++ is_pascal_string_type (struct type *, int *, int *, int *, ++ struct type **, char **); + +-extern void pascal_printchar (int, struct ui_file *); ++extern void pascal_printchar (int, struct type *, struct ui_file *); + +-extern void pascal_printstr (struct ui_file *, const gdb_byte *, +- unsigned int, int, int, ++extern void pascal_printstr (struct ui_file *, struct type *, const gdb_byte *, ++ unsigned int, int, + const struct value_print_options *); + + extern struct type **const (pascal_builtin_types[]); +diff --git a/gdb/p-valprint.c b/gdb/p-valprint.c +index 27ae619..29f0e6d 100644 +--- a/gdb/p-valprint.c ++++ b/gdb/p-valprint.c +@@ -61,7 +61,7 @@ pascal_val_print (struct type *type, const gdb_byte *valaddr, + struct type *elttype; + unsigned eltlen; + int length_pos, length_size, string_pos; +- int char_size; ++ struct type *char_type; + LONGEST val; + CORE_ADDR addr; + +@@ -100,8 +100,9 @@ pascal_val_print (struct type *type, const gdb_byte *valaddr, + len = temp_len; + } + +- LA_PRINT_STRING (stream, valaddr + embedded_offset, len, +- eltlen, 0, options); ++ LA_PRINT_STRING (stream, TYPE_TARGET_TYPE (type), ++ valaddr + embedded_offset, len, 0, ++ options); + i = len; + } + else +@@ -175,8 +176,7 @@ pascal_val_print (struct type *type, const gdb_byte *valaddr, + && addr != 0) + { + /* no wide string yet */ +- i = val_print_string (addr, -1, TYPE_LENGTH (elttype), stream, +- options); ++ i = val_print_string (elttype, addr, -1, stream, options); + } + /* also for pointers to pascal strings */ + /* Note: this is Free Pascal specific: +@@ -184,7 +184,7 @@ pascal_val_print (struct type *type, const gdb_byte *valaddr, + Pascal strings are mapped to records + with lowercase names PM */ + if (is_pascal_string_type (elttype, &length_pos, &length_size, +- &string_pos, &char_size, NULL) ++ &string_pos, &char_type, NULL) + && addr != 0) + { + ULONGEST string_length; +@@ -193,7 +193,7 @@ pascal_val_print (struct type *type, const gdb_byte *valaddr, + read_memory (addr + length_pos, buffer, length_size); + string_length = extract_unsigned_integer (buffer, length_size); + xfree (buffer); +- i = val_print_string (addr + string_pos, string_length, char_size, stream, options); ++ i = val_print_string (char_type ,addr + string_pos, string_length, stream, options); + } + else if (pascal_object_is_vtbl_member (type)) + { +@@ -298,10 +298,10 @@ pascal_val_print (struct type *type, const gdb_byte *valaddr, + else + { + if (is_pascal_string_type (type, &length_pos, &length_size, +- &string_pos, &char_size, NULL)) ++ &string_pos, &char_type, NULL)) + { + len = extract_unsigned_integer (valaddr + embedded_offset + length_pos, length_size); +- LA_PRINT_STRING (stream, valaddr + embedded_offset + string_pos, len, char_size, 0, options); ++ LA_PRINT_STRING (stream, char_type, valaddr + embedded_offset + string_pos, len, 0, options); + } + else + pascal_object_print_value_fields (type, valaddr + embedded_offset, address, stream, +@@ -426,7 +426,7 @@ pascal_val_print (struct type *type, const gdb_byte *valaddr, + else + fprintf_filtered (stream, "%d", (int) val); + fputs_filtered (" ", stream); +- LA_PRINT_CHAR ((unsigned char) val, stream); ++ LA_PRINT_CHAR ((unsigned char) val, type, stream); + } + break; + +@@ -931,7 +931,7 @@ pascal_object_print_static_field (struct value *val, + + if (TYPE_CODE (type) == TYPE_CODE_STRUCT) + { +- CORE_ADDR *first_dont_print; ++ CORE_ADDR *first_dont_print, addr; + int i; + + first_dont_print +@@ -941,7 +941,7 @@ pascal_object_print_static_field (struct value *val, + + while (--i >= 0) + { +- if (VALUE_ADDRESS (val) == first_dont_print[i]) ++ if (value_address (val) == first_dont_print[i]) + { + fputs_filtered ("", + stream); +@@ -949,11 +949,12 @@ pascal_object_print_static_field (struct value *val, + } + } + +- obstack_grow (&dont_print_statmem_obstack, (char *) &VALUE_ADDRESS (val), ++ addr = value_address (val); ++ obstack_grow (&dont_print_statmem_obstack, (char *) &addr, + sizeof (CORE_ADDR)); + + CHECK_TYPEDEF (type); +- pascal_object_print_value_fields (type, value_contents (val), VALUE_ADDRESS (val), ++ pascal_object_print_value_fields (type, value_contents (val), value_address (val), + stream, recurse, options, NULL, 1); + return; + } +diff --git a/gdb/parse.c b/gdb/parse.c +index eee1f8e..66aaf6a 100644 +--- a/gdb/parse.c ++++ b/gdb/parse.c +@@ -306,7 +306,7 @@ write_exp_elt_intern (struct internalvar *expelt) + strings with embedded null bytes, as is required for some languages. + + Don't be fooled by the fact that the string is null byte terminated, +- this is strictly for the convenience of debugging gdb itself. Gdb ++ this is strictly for the convenience of debugging gdb itself. + Gdb does not depend up the string being null terminated, since the + actual length is recorded in expression elements at each end of the + string. The null byte is taken into consideration when computing how +@@ -352,6 +352,65 @@ write_exp_string (struct stoken str) + write_exp_elt_longcst ((LONGEST) len); + } + ++/* Add a vector of string constants to the end of the expression. ++ ++ This adds an OP_STRING operation, but encodes the contents ++ differently from write_exp_string. The language is expected to ++ handle evaluation of this expression itself. ++ ++ After the usual OP_STRING header, TYPE is written into the ++ expression as a long constant. The interpretation of this field is ++ up to the language evaluator. ++ ++ Next, each string in VEC is written. The length is written as a ++ long constant, followed by the contents of the string. */ ++ ++void ++write_exp_string_vector (int type, struct stoken_vector *vec) ++{ ++ int i, n_slots, len; ++ ++ /* Compute the size. We compute the size in number of slots to ++ avoid issues with string padding. */ ++ n_slots = 0; ++ for (i = 0; i < vec->len; ++i) ++ { ++ /* One slot for the length of this element, plus the number of ++ slots needed for this string. */ ++ n_slots += 1 + BYTES_TO_EXP_ELEM (vec->tokens[i].length); ++ } ++ ++ /* One more slot for the type of the string. */ ++ ++n_slots; ++ ++ /* Now compute a phony string length. */ ++ len = EXP_ELEM_TO_BYTES (n_slots) - 1; ++ ++ n_slots += 4; ++ if ((expout_ptr + n_slots) >= expout_size) ++ { ++ expout_size = max (expout_size * 2, expout_ptr + n_slots + 10); ++ expout = (struct expression *) ++ xrealloc ((char *) expout, (sizeof (struct expression) ++ + EXP_ELEM_TO_BYTES (expout_size))); ++ } ++ ++ write_exp_elt_opcode (OP_STRING); ++ write_exp_elt_longcst (len); ++ write_exp_elt_longcst (type); ++ ++ for (i = 0; i < vec->len; ++i) ++ { ++ write_exp_elt_longcst (vec->tokens[i].length); ++ memcpy (&expout->elts[expout_ptr], vec->tokens[i].ptr, ++ vec->tokens[i].length); ++ expout_ptr += BYTES_TO_EXP_ELEM (vec->tokens[i].length); ++ } ++ ++ write_exp_elt_longcst (len); ++ write_exp_elt_opcode (OP_STRING); ++} ++ + /* Add a bitstring constant to the end of the expression. + + Bitstring constants are stored by first writing an expression element +@@ -777,6 +836,15 @@ operator_length_standard (struct expression *expr, int endpos, + args = 1 + longest_to_int (expr->elts[endpos - 2].longconst); + break; + ++ case TYPE_INSTANCE: ++ oplen = 4 + longest_to_int (expr->elts[endpos - 2].longconst); ++ args = 1; ++ break; ++ ++ case TYPE_INSTANCE_LOOKUP: ++ oplen = 3; ++ break; ++ + case OP_OBJC_MSGCALL: /* Objective C message (method) call */ + oplen = 4; + args = 1 + longest_to_int (expr->elts[endpos - 2].longconst); +diff --git a/gdb/parser-defs.h b/gdb/parser-defs.h +index 2c4b755..cbda9c3 100644 +--- a/gdb/parser-defs.h ++++ b/gdb/parser-defs.h +@@ -69,6 +69,22 @@ struct stoken + int length; + }; + ++struct typed_stoken ++ { ++ /* A language-specific type field. */ ++ int type; ++ /* Pointer to first byte of char-string or first bit of bit-string */ ++ char *ptr; ++ /* Length of string in bytes for char-string or bits for bit-string */ ++ int length; ++ }; ++ ++struct stoken_vector ++ { ++ int len; ++ struct typed_stoken *tokens; ++ }; ++ + struct ttype + { + struct stoken stoken; +@@ -130,6 +146,8 @@ extern void write_exp_elt_intern (struct internalvar *); + + extern void write_exp_string (struct stoken); + ++void write_exp_string_vector (int type, struct stoken_vector *vec); ++ + extern void write_exp_bitstring (struct stoken); + + extern void write_exp_elt_block (struct block *); +diff --git a/gdb/ppc-linux-tdep.c b/gdb/ppc-linux-tdep.c +index d08d4fc..c2bbdf9 100644 +--- a/gdb/ppc-linux-tdep.c ++++ b/gdb/ppc-linux-tdep.c +@@ -38,6 +38,7 @@ + #include "trad-frame.h" + #include "frame-unwind.h" + #include "tramp-frame.h" ++#include "linux-tdep.h" + + #include "features/rs6000/powerpc-32l.c" + #include "features/rs6000/powerpc-altivec32l.c" +@@ -53,6 +54,9 @@ + #include "features/rs6000/powerpc-isa205-vsx64l.c" + #include "features/rs6000/powerpc-e500l.c" + ++/* The syscall's XML filename for PPC and PPC64. */ ++#define XML_SYSCALL_FILENAME_PPC "syscalls/ppc-linux.xml" ++#define XML_SYSCALL_FILENAME_PPC64 "syscalls/ppc64-linux.xml" + + /* ppc_linux_memory_remove_breakpoints attempts to remove a breakpoint + in much the same fashion as memory_remove_breakpoint in mem-break.c, +@@ -1009,6 +1013,38 @@ ppc_linux_trap_reg_p (struct gdbarch *gdbarch) + && register_size (gdbarch, PPC_TRAP_REGNUM) > 0; + } + ++/* Return the current system call's number present in the ++ r0 register. When the function fails, it returns -1. */ ++static LONGEST ++ppc_linux_get_syscall_number (struct gdbarch *gdbarch, ++ ptid_t ptid) ++{ ++ struct regcache *regcache = get_thread_regcache (ptid); ++ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); ++ struct cleanup *cleanbuf; ++ /* The content of a register */ ++ gdb_byte *buf; ++ /* The result */ ++ LONGEST ret; ++ ++ /* Make sure we're in a 32- or 64-bit machine */ ++ gdb_assert (tdep->wordsize == 4 || tdep->wordsize == 8); ++ ++ buf = (gdb_byte *) xmalloc (tdep->wordsize * sizeof (gdb_byte)); ++ ++ cleanbuf = make_cleanup (xfree, buf); ++ ++ /* Getting the system call number from the register. ++ When dealing with PowerPC architecture, this information ++ is stored at 0th register. */ ++ regcache_cooked_read (regcache, tdep->ppc_gp0_regnum, buf); ++ ++ ret = extract_signed_integer (buf, tdep->wordsize); ++ do_cleanups (cleanbuf); ++ ++ return ret; ++} ++ + static void + ppc_linux_write_pc (struct regcache *regcache, CORE_ADDR pc) + { +@@ -1069,6 +1105,9 @@ ppc_linux_init_abi (struct gdbarch_info info, + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + struct tdesc_arch_data *tdesc_data = (void *) info.tdep_info; + ++ /* Initializing common methods. */ ++ linux_tdep_init (gdbarch); ++ + /* PPC GNU/Linux uses either 64-bit or 128-bit long doubles; where + 128-bit, they are IBM long double, not IEEE quad long double as + in the System V ABI PowerPC Processor Supplement. We can safely +@@ -1080,6 +1119,9 @@ ppc_linux_init_abi (struct gdbarch_info info, + /* Handle inferior calls during interrupted system calls. */ + set_gdbarch_write_pc (gdbarch, ppc_linux_write_pc); + ++ /* Get the syscall number from the arch's register. */ ++ set_gdbarch_get_syscall_number (gdbarch, ppc_linux_get_syscall_number); ++ + if (tdep->wordsize == 4) + { + /* Until November 2001, gcc did not comply with the 32 bit SysV +@@ -1099,6 +1141,9 @@ ppc_linux_init_abi (struct gdbarch_info info, + set_solib_svr4_fetch_link_map_offsets + (gdbarch, svr4_ilp32_fetch_link_map_offsets); + ++ /* Setting the correct XML syscall filename. */ ++ set_gdbarch_xml_syscall_filename (gdbarch, XML_SYSCALL_FILENAME_PPC); ++ + /* Trampolines. */ + tramp_frame_prepend_unwinder (gdbarch, &ppc32_linux_sigaction_tramp_frame); + tramp_frame_prepend_unwinder (gdbarch, &ppc32_linux_sighandler_tramp_frame); +@@ -1116,6 +1161,9 @@ ppc_linux_init_abi (struct gdbarch_info info, + set_solib_svr4_fetch_link_map_offsets + (gdbarch, svr4_lp64_fetch_link_map_offsets); + ++ /* Setting the correct XML syscall filename. */ ++ set_gdbarch_xml_syscall_filename (gdbarch, XML_SYSCALL_FILENAME_PPC64); ++ + /* Trampolines. */ + tramp_frame_prepend_unwinder (gdbarch, &ppc64_linux_sigaction_tramp_frame); + tramp_frame_prepend_unwinder (gdbarch, &ppc64_linux_sighandler_tramp_frame); +diff --git a/gdb/printcmd.c b/gdb/printcmd.c +index 375f82e..8c3f476 100644 +--- a/gdb/printcmd.c ++++ b/gdb/printcmd.c +@@ -43,6 +43,7 @@ + #include "disasm.h" + #include "dfp.h" + #include "valprint.h" ++#include "charset.h" + + #ifdef TUI + #include "tui/tui.h" /* For tui_active et.al. */ +@@ -62,11 +63,15 @@ struct format_data + int count; + char format; + char size; ++ ++ /* True if the value should be printed raw -- that is, bypassing ++ python-based formatters. */ ++ unsigned char raw; + }; + + /* Last specified output format. */ + +-static char last_format = 'x'; ++static char last_format = 0; + + /* Last specified examination size. 'b', 'h', 'w' or `q'. */ + +@@ -175,6 +180,7 @@ decode_format (char **string_ptr, int oformat, int osize) + val.format = '?'; + val.size = '?'; + val.count = 1; ++ val.raw = 0; + + if (*p >= '0' && *p <= '9') + val.count = atoi (p); +@@ -187,6 +193,11 @@ decode_format (char **string_ptr, int oformat, int osize) + { + if (*p == 'b' || *p == 'h' || *p == 'w' || *p == 'g') + val.size = *p++; ++ else if (*p == 'r') ++ { ++ val.raw = 1; ++ p++; ++ } + else if (*p >= 'a' && *p <= 'z') + val.format = *p++; + else +@@ -264,24 +275,27 @@ print_formatted (struct value *val, int size, + int len = TYPE_LENGTH (type); + + if (VALUE_LVAL (val) == lval_memory) +- next_address = VALUE_ADDRESS (val) + len; ++ next_address = value_address (val) + len; + + if (size) + { + switch (options->format) + { + case 's': +- /* FIXME: Need to handle wchar_t's here... */ +- next_address = VALUE_ADDRESS (val) +- + val_print_string (VALUE_ADDRESS (val), -1, 1, stream, +- options); ++ { ++ struct type *elttype = value_type (val); ++ next_address = (value_address (val) ++ + val_print_string (elttype, ++ value_address (val), -1, ++ stream, options)); ++ } + return; + + case 'i': + /* We often wrap here if there are long symbolic names. */ + wrap_here (" "); +- next_address = (VALUE_ADDRESS (val) +- + gdb_print_insn (VALUE_ADDRESS (val), stream, ++ next_address = (value_address (val) ++ + gdb_print_insn (value_address (val), stream, + &branch_delay_insns)); + return; + } +@@ -369,7 +383,7 @@ print_scalar_formatted (const void *valaddr, struct type *type, + print_hex_chars (stream, valaddr, len, byte_order); + return; + case 'c': +- print_char_chars (stream, valaddr, len, byte_order); ++ print_char_chars (stream, type, valaddr, len, byte_order); + return; + default: + break; +@@ -865,6 +879,7 @@ print_command_1 (char *exp, int inspect, int voidprint) + fmt.count = 1; + fmt.format = 0; + fmt.size = 0; ++ fmt.raw = 0; + } + + if (exp && *exp) +@@ -878,6 +893,11 @@ print_command_1 (char *exp, int inspect, int voidprint) + else + val = access_value_history (0); + ++ /* Do not try to OBJECT_ADDRESS_SET here anything. We are interested in the ++ source variable base addresses as found by READ_VAR_VALUE. The value here ++ can be already a calculated expression address inappropriate for ++ DW_OP_push_object_address. */ ++ + if (voidprint || (val && value_type (val) && + TYPE_CODE (value_type (val)) != TYPE_CODE_VOID)) + { +@@ -900,6 +920,7 @@ print_command_1 (char *exp, int inspect, int voidprint) + + get_formatted_print_options (&opts, format); + opts.inspect_it = inspect; ++ opts.raw = fmt.raw; + + print_formatted (val, fmt.size, &opts, gdb_stdout); + printf_filtered ("\n"); +@@ -950,6 +971,7 @@ output_command (char *exp, int from_tty) + struct value_print_options opts; + + fmt.size = 0; ++ fmt.raw = 0; + + if (exp && *exp == '/') + { +@@ -967,6 +989,7 @@ output_command (char *exp, int from_tty) + annotate_value_begin (value_type (val)); + + get_formatted_print_options (&opts, format); ++ opts.raw = fmt.raw; + print_formatted (val, fmt.size, &opts, gdb_stdout); + + annotate_value_end (); +@@ -1287,9 +1310,10 @@ x_command (char *exp, int from_tty) + struct cleanup *old_chain; + struct value *val; + +- fmt.format = last_format; ++ fmt.format = last_format ? last_format : 'x'; + fmt.size = last_size; + fmt.count = 1; ++ fmt.raw = 0; + + if (exp && *exp == '/') + { +@@ -1316,7 +1340,7 @@ x_command (char *exp, int from_tty) + if (/* last_format == 'i' && */ + TYPE_CODE (value_type (val)) == TYPE_CODE_FUNC + && VALUE_LVAL (val) == lval_memory) +- next_address = VALUE_ADDRESS (val); ++ next_address = value_address (val); + else + next_address = value_as_address (val); + do_cleanups (old_chain); +@@ -1393,6 +1417,7 @@ display_command (char *exp, int from_tty) + fmt.format = 0; + fmt.size = 0; + fmt.count = 0; ++ fmt.raw = 0; + } + + innermost_block = 0; +@@ -1585,6 +1610,7 @@ do_one_display (struct display *d) + annotate_display_expression (); + + get_formatted_print_options (&opts, d->format.format); ++ opts.raw = d->format.raw; + print_formatted (evaluate_expression (d->exp), + d->format.size, &opts, gdb_stdout); + printf_filtered ("\n"); +@@ -1865,7 +1891,8 @@ printf_command (char *arg, int from_tty) + + enum argclass + { +- int_arg, long_arg, long_long_arg, ptr_arg, string_arg, ++ int_arg, long_arg, long_long_arg, ptr_arg, ++ string_arg, wide_string_arg, wide_char_arg, + double_arg, long_double_arg, decfloat_arg + }; + enum argclass *argclass; +@@ -1997,8 +2024,8 @@ printf_command (char *arg, int from_tty) + break; + + case 'c': +- this_argclass = int_arg; +- if (lcount || seen_h || seen_big_l) ++ this_argclass = lcount == 0 ? int_arg : wide_char_arg; ++ if (lcount > 1 || seen_h || seen_big_l) + bad = 1; + if (seen_prec || seen_zero || seen_space || seen_plus) + bad = 1; +@@ -2013,8 +2040,8 @@ printf_command (char *arg, int from_tty) + break; + + case 's': +- this_argclass = string_arg; +- if (lcount || seen_h || seen_big_l) ++ this_argclass = lcount == 0 ? string_arg : wide_string_arg; ++ if (lcount > 1 || seen_h || seen_big_l) + bad = 1; + if (seen_zero || seen_space || seen_plus) + bad = 1; +@@ -2066,6 +2093,15 @@ printf_command (char *arg, int from_tty) + last_arg[length_before_ll + lcount]; + current_substring += length_before_ll + 4; + } ++ else if (this_argclass == wide_string_arg ++ || this_argclass == wide_char_arg) ++ { ++ /* Convert %ls or %lc to %s. */ ++ int length_before_ls = f - last_arg - 2; ++ strncpy (current_substring, last_arg, length_before_ls); ++ strcpy (current_substring + length_before_ls, "s"); ++ current_substring += length_before_ls + 2; ++ } + else + { + strncpy (current_substring, last_arg, f - last_arg); +@@ -2130,6 +2166,76 @@ printf_command (char *arg, int from_tty) + printf_filtered (current_substring, (char *) str); + } + break; ++ case wide_string_arg: ++ { ++ gdb_byte *str; ++ CORE_ADDR tem; ++ int j; ++ struct type *wctype = lookup_typename ("wchar_t", NULL, 0); ++ int wcwidth = TYPE_LENGTH (wctype); ++ gdb_byte *buf = alloca (wcwidth); ++ struct obstack output; ++ struct cleanup *inner_cleanup; ++ ++ tem = value_as_address (val_args[i]); ++ ++ /* This is a %s argument. Find the length of the string. */ ++ for (j = 0;; j += wcwidth) ++ { ++ QUIT; ++ read_memory (tem + j, buf, wcwidth); ++ if (extract_unsigned_integer (buf, wcwidth) == 0) ++ break; ++ } ++ ++ /* Copy the string contents into a string inside GDB. */ ++ str = (gdb_byte *) alloca (j + wcwidth); ++ if (j != 0) ++ read_memory (tem, str, j); ++ memset (&str[j], 0, wcwidth); ++ ++ obstack_init (&output); ++ inner_cleanup = make_cleanup_obstack_free (&output); ++ ++ convert_between_encodings (target_wide_charset (), ++ host_charset (), ++ str, j, wcwidth, ++ &output, translit_char); ++ obstack_grow_str0 (&output, ""); ++ ++ printf_filtered (current_substring, obstack_base (&output)); ++ do_cleanups (inner_cleanup); ++ } ++ break; ++ case wide_char_arg: ++ { ++ struct type *wctype = lookup_typename ("wchar_t", NULL, 0); ++ struct type *valtype; ++ struct obstack output; ++ struct cleanup *inner_cleanup; ++ const gdb_byte *bytes; ++ ++ valtype = value_type (val_args[i]); ++ if (TYPE_LENGTH (valtype) != TYPE_LENGTH (wctype) ++ || TYPE_CODE (valtype) != TYPE_CODE_INT) ++ error (_("expected wchar_t argument for %%lc")); ++ ++ bytes = value_contents (val_args[i]); ++ ++ obstack_init (&output); ++ inner_cleanup = make_cleanup_obstack_free (&output); ++ ++ convert_between_encodings (target_wide_charset (), ++ host_charset (), ++ bytes, TYPE_LENGTH (valtype), ++ TYPE_LENGTH (valtype), ++ &output, translit_char); ++ obstack_grow_str0 (&output, ""); ++ ++ printf_filtered (current_substring, obstack_base (&output)); ++ do_cleanups (inner_cleanup); ++ } ++ break; + case double_arg: + { + struct type *type = value_type (val_args[i]); +diff --git a/gdb/python/lib/gdb/FrameIterator.py b/gdb/python/lib/gdb/FrameIterator.py +new file mode 100644 +index 0000000..87fb074 +--- /dev/null ++++ b/gdb/python/lib/gdb/FrameIterator.py +@@ -0,0 +1,33 @@ ++# Iterator over frames. ++ ++# Copyright (C) 2008 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++class FrameIterator: ++ """An iterator that iterates over frames.""" ++ ++ def __init__ (self, frame): ++ "Initialize a FrameIterator. FRAME is the starting frame." ++ self.frame = frame ++ ++ def __iter__ (self): ++ return self ++ ++ def next (self): ++ result = self.frame ++ if result == None: ++ raise StopIteration ++ self.frame = result.older () ++ return result +diff --git a/gdb/python/lib/gdb/__init__.py b/gdb/python/lib/gdb/__init__.py +new file mode 100644 +index 0000000..b375c68 +--- /dev/null ++++ b/gdb/python/lib/gdb/__init__.py +@@ -0,0 +1,19 @@ ++# Startup code. ++ ++# Copyright (C) 2008 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++# Load the require command by default. ++import gdb.command.require +diff --git a/gdb/python/lib/gdb/backtrace.py b/gdb/python/lib/gdb/backtrace.py +new file mode 100644 +index 0000000..2baab5f +--- /dev/null ++++ b/gdb/python/lib/gdb/backtrace.py +@@ -0,0 +1,42 @@ ++# Filtering backtrace. ++ ++# Copyright (C) 2008 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++import gdb ++import itertools ++ ++# Our only exports. ++__all__ = ['push_frame_filter', 'create_frame_filter'] ++ ++frame_filter = None ++ ++def push_frame_filter (constructor): ++ """Register a new backtrace filter class with the 'backtrace' command. ++The filter will be passed an iterator as an argument. The iterator ++will return gdb.Frame-like objects. The filter should in turn act as ++an iterator returning such objects.""" ++ global frame_filter ++ if frame_filter == None: ++ frame_filter = constructor ++ else: ++ frame_filter = lambda iterator: constructor (frame_filter (iterator)) ++ ++def create_frame_filter (iter): ++ global frame_filter ++ if frame_filter is None: ++ return iter ++ return frame_filter (iter) ++ +diff --git a/gdb/python/lib/gdb/command/__init__.py b/gdb/python/lib/gdb/command/__init__.py +new file mode 100644 +index 0000000..8b13789 +--- /dev/null ++++ b/gdb/python/lib/gdb/command/__init__.py +@@ -0,0 +1 @@ ++ +diff --git a/gdb/python/lib/gdb/command/alias.py b/gdb/python/lib/gdb/command/alias.py +new file mode 100644 +index 0000000..96b6618 +--- /dev/null ++++ b/gdb/python/lib/gdb/command/alias.py +@@ -0,0 +1,59 @@ ++# Alias command. ++ ++# Copyright (C) 2008 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++import gdb ++ ++class AliasImplementation (gdb.Command): ++ def __init__ (self, name, real, doc): ++ # Have to set __doc__ before the super init call. ++ # It would be nice if gdb's help looked up __doc__ dynamically. ++ self.__doc__ = doc ++ # Note: no good way to complete :( ++ super (AliasImplementation, self).__init__ (name, gdb.COMMAND_NONE) ++ self.real = real ++ ++ def invoke(self, arg, from_tty): ++ gdb.execute (self.real + ' ' + arg, from_tty) ++ ++class AliasCommand (gdb.Command): ++ """Alias one command to another. ++In the simplest form, the first word is the name of the alias, and ++the remaining words are the the expansion. ++An '=' by itself can be used to define a multi-word alias; words ++before the '=' are the name of the new command.""" ++ ++ def __init__ (self): ++ # Completion is not quite right here. ++ super (AliasCommand, self).__init__ ("alias", gdb.COMMAND_NONE, ++ gdb.COMPLETE_COMMAND) ++ ++ def invoke (self, arg, from_tty): ++ self.dont_repeat () ++ # Without some form of quoting we can't alias a multi-word ++ # command to another command. ++ args = arg.split() ++ try: ++ start = args.index ('=') ++ end = start + 1 ++ except ValueError: ++ start = 1 ++ end = 1 ++ target = " ".join(args[end:]) ++ AliasImplementation (" ".join (args[0:start]), target, ++ "This command is an alias for '%s'." % target) ++ ++AliasCommand() +diff --git a/gdb/python/lib/gdb/command/backtrace.py b/gdb/python/lib/gdb/command/backtrace.py +new file mode 100644 +index 0000000..f07696e +--- /dev/null ++++ b/gdb/python/lib/gdb/command/backtrace.py +@@ -0,0 +1,197 @@ ++# New backtrace command. ++ ++# Copyright (C) 2008 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++import gdb ++import gdb.backtrace ++import itertools ++from gdb.FrameIterator import FrameIterator ++import sys ++ ++class FrameWrapper: ++ def __init__ (self, frame): ++ self.frame = frame; ++ ++ def write_symbol (self, stream, sym, block): ++ if len (sym.linkage_name): ++ nsym, is_field_of_this = gdb.lookup_symbol (sym.linkage_name, block) ++ if nsym.addr_class != gdb.SYMBOL_LOC_REGISTER: ++ sym = nsym ++ ++ stream.write (sym.print_name + "=") ++ try: ++ val = self.frame.read_var (sym) ++ if val != None: ++ val = str (val) ++ # FIXME: would be nice to have a more precise exception here. ++ except RuntimeError, text: ++ val = text ++ if val == None: ++ stream.write ("???") ++ else: ++ stream.write (str (val)) ++ ++ def print_frame_locals (self, stream, func): ++ if not func: ++ return ++ ++ first = True ++ block = func.value ++ ++ for sym in block: ++ if sym.is_argument: ++ continue; ++ ++ self.write_symbol (stream, sym, block) ++ stream.write ('\n') ++ ++ def print_frame_args (self, stream, func): ++ if not func: ++ return ++ ++ first = True ++ block = func.value ++ ++ for sym in block: ++ if not sym.is_argument: ++ continue; ++ ++ if not first: ++ stream.write (", ") ++ ++ self.write_symbol (stream, sym, block) ++ first = False ++ ++ # FIXME: this should probably just be a method on gdb.Frame. ++ # But then we need stream wrappers. ++ def describe (self, stream, full): ++ if self.frame.type () == gdb.DUMMY_FRAME: ++ stream.write (" \n") ++ elif self.frame.type () == gdb.SIGTRAMP_FRAME: ++ stream.write (" \n") ++ else: ++ sal = self.frame.find_sal () ++ pc = self.frame.pc () ++ name = self.frame.name () ++ if not name: ++ name = "??" ++ if pc != sal.pc or not sal.symtab: ++ stream.write (" 0x%08x in" % pc) ++ stream.write (" " + name + " (") ++ ++ func = gdb.find_pc_function (self.frame.addr_in_block ()) ++ self.print_frame_args (stream, func) ++ ++ stream.write (")") ++ ++ if sal.symtab and sal.symtab.filename: ++ stream.write (" at " + sal.symtab.filename) ++ stream.write (":" + str (sal.line)) ++ ++ if not self.frame.name () or (not sal.symtab or not sal.symtab.filename): ++ lib = gdb.solib_address (pc) ++ if lib: ++ stream.write (" from " + lib) ++ ++ stream.write ("\n") ++ ++ if full: ++ self.print_frame_locals (stream, func) ++ ++ def __getattr__ (self, name): ++ return getattr (self.frame, name) ++ ++class ReverseBacktraceParameter (gdb.Parameter): ++ """The new-backtrace command can show backtraces in 'reverse' order. ++This means that the innermost frame will be printed last. ++Note that reverse backtraces are more expensive to compute.""" ++ ++ set_doc = "Enable or disable reverse backtraces." ++ show_doc = "Show whether backtraces will be printed in reverse order." ++ ++ def __init__(self): ++ gdb.Parameter.__init__ (self, "reverse-backtrace", ++ gdb.COMMAND_STACK, gdb.PARAM_BOOLEAN) ++ # Default to compatibility with gdb. ++ self.value = False ++ ++class FilteringBacktrace (gdb.Command): ++ """Print backtrace of all stack frames, or innermost COUNT frames. ++With a negative argument, print outermost -COUNT frames. ++Use of the 'full' qualifier also prints the values of the local variables. ++Use of the 'raw' qualifier avoids any filtering by loadable modules. ++""" ++ ++ def __init__ (self): ++ # FIXME: this is not working quite well enough to replace ++ # "backtrace" yet. ++ gdb.Command.__init__ (self, "new-backtrace", gdb.COMMAND_STACK) ++ self.reverse = ReverseBacktraceParameter() ++ ++ def reverse_iter (self, iter): ++ result = [] ++ for item in iter: ++ result.append (item) ++ result.reverse() ++ return result ++ ++ def final_n (self, iter, x): ++ result = [] ++ for item in iter: ++ result.append (item) ++ return result[x:] ++ ++ def invoke (self, arg, from_tty): ++ i = 0 ++ count = 0 ++ filter = True ++ full = False ++ ++ for word in arg.split (" "): ++ if word == '': ++ continue ++ elif word == 'raw': ++ filter = False ++ elif word == 'full': ++ full = True ++ else: ++ count = int (word) ++ ++ # FIXME: provide option to start at selected frame ++ # However, should still number as if starting from newest ++ iter = itertools.imap (FrameWrapper, ++ FrameIterator (gdb.newest_frame ())) ++ if filter: ++ iter = gdb.backtrace.create_frame_filter (iter) ++ ++ # Now wrap in an iterator that numbers the frames. ++ iter = itertools.izip (itertools.count (0), iter) ++ ++ # Reverse if the user wanted that. ++ if self.reverse.value: ++ iter = self.reverse_iter (iter) ++ ++ # Extract sub-range user wants. ++ if count < 0: ++ iter = self.final_n (iter, count) ++ elif count > 0: ++ iter = itertools.islice (iter, 0, count) ++ ++ for pair in iter: ++ sys.stdout.write ("#%-2d" % pair[0]) ++ pair[1].describe (sys.stdout, full) ++ ++FilteringBacktrace() +diff --git a/gdb/python/lib/gdb/command/ignore_errors.py b/gdb/python/lib/gdb/command/ignore_errors.py +new file mode 100644 +index 0000000..6fa48ff +--- /dev/null ++++ b/gdb/python/lib/gdb/command/ignore_errors.py +@@ -0,0 +1,37 @@ ++# Ignore errors in user commands. ++ ++# Copyright (C) 2008 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++import gdb ++ ++class IgnoreErrorsCommand (gdb.Command): ++ """Execute a single command, ignoring all errors. ++Only one-line commands are supported. ++This is primarily useful in scripts.""" ++ ++ def __init__ (self): ++ super (IgnoreErrorsCommand, self).__init__ ("ignore-errors", ++ gdb.COMMAND_OBSCURE, ++ # FIXME... ++ gdb.COMPLETE_COMMAND) ++ ++ def invoke (self, arg, from_tty): ++ try: ++ gdb.execute (arg, from_tty) ++ except: ++ pass ++ ++IgnoreErrorsCommand () +diff --git a/gdb/python/lib/gdb/command/pahole.py b/gdb/python/lib/gdb/command/pahole.py +new file mode 100644 +index 0000000..569b816 +--- /dev/null ++++ b/gdb/python/lib/gdb/command/pahole.py +@@ -0,0 +1,81 @@ ++# pahole command for gdb ++ ++# Copyright (C) 2008 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++import gdb ++ ++class Pahole (gdb.Command): ++ """Show the holes in a structure. ++This command takes a single argument, a type name. ++It prints the type and displays comments showing where holes are.""" ++ ++ def __init__ (self): ++ super (Pahole, self).__init__ ("pahole", gdb.COMMAND_NONE, ++ gdb.COMPLETE_SYMBOL) ++ ++ @staticmethod ++ def strip (type): ++ while type.code () == gdb.TYPE_CODE_TYPEDEF: ++ type = type.target () ++ return type ++ ++ def pahole (self, type, level, name): ++ if name is None: ++ name = '' ++ tag = type.tag () ++ if tag is None: ++ tag = '' ++ print '%sstruct %s {' % (' ' * (2 * level), tag) ++ bitpos = 0 ++ for field in type.fields (): ++ # Skip static fields. ++ if not hasattr (field, ('bitpos')): ++ continue ++ ++ ftype = self.strip (field.type) ++ ++ if bitpos != field.bitpos: ++ hole = field.bitpos - bitpos ++ print ' /* XXX %d bit hole, try to pack */' % hole ++ bitpos = field.bitpos ++ if field.bitsize > 0: ++ fieldsize = field.bitsize ++ else: ++ # TARGET_CHAR_BIT here... ++ fieldsize = 8 * ftype.sizeof () ++ ++ # TARGET_CHAR_BIT ++ print ' /* %3d %3d */' % (int (bitpos / 8), int (fieldsize / 8)), ++ bitpos = bitpos + fieldsize ++ ++ if ftype.code () == gdb.TYPE_CODE_STRUCT: ++ self.pahole (ftype, level + 1, field.name) ++ else: ++ print ' ' * (2 + 2 * level), ++ print '%s %s' % (str (ftype), field.name) ++ ++ print ' ' * (14 + 2 * level), ++ print '} %s' % name ++ ++ def invoke (self, arg, from_tty): ++ type = gdb.Type (arg) ++ type = self.strip (type) ++ if type.code () != gdb.TYPE_CODE_STRUCT: ++ raise TypeError, '%s is not a struct type' % arg ++ print ' ' * 14, ++ self.pahole (type, 0, '') ++ ++Pahole() +diff --git a/gdb/python/lib/gdb/command/require.py b/gdb/python/lib/gdb/command/require.py +new file mode 100644 +index 0000000..1fbc1e8 +--- /dev/null ++++ b/gdb/python/lib/gdb/command/require.py +@@ -0,0 +1,57 @@ ++# Demand-loading commands. ++ ++# Copyright (C) 2008, 2009 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++import gdb ++import os ++ ++class RequireCommand (gdb.Command): ++ """Prefix command for requiring features.""" ++ ++ def __init__ (self): ++ super (RequireCommand, self).__init__ ("require", ++ gdb.COMMAND_SUPPORT, ++ gdb.COMPLETE_NONE, ++ True) ++ ++class RequireSubcommand (gdb.Command): ++ """Demand-load a command by name.""" ++ ++ def __init__ (self, name): ++ self.__doc__ = "Demand-load a %s by name." % name ++ super (RequireSubcommand, self).__init__ ("require %s" % name, ++ gdb.COMMAND_SUPPORT) ++ self.name = name ++ ++ def invoke (self, arg, from_tty): ++ for cmd in arg.split(): ++ exec ('import gdb.' + self.name + '.' + cmd, globals ()) ++ ++ def complete (self, text, word): ++ dir = gdb.pythondir + '/gdb/' + self.name ++ result = [] ++ for file in os.listdir(dir): ++ if not file.startswith (word) or not file.endswith ('.py'): ++ continue ++ feature = file[0:-3] ++ if feature == 'require' or feature == '__init__': ++ continue ++ result.append (feature) ++ return result ++ ++RequireCommand() ++RequireSubcommand("command") ++RequireSubcommand("function") +diff --git a/gdb/python/lib/gdb/command/save_breakpoints.py b/gdb/python/lib/gdb/command/save_breakpoints.py +new file mode 100644 +index 0000000..90e07db +--- /dev/null ++++ b/gdb/python/lib/gdb/command/save_breakpoints.py +@@ -0,0 +1,65 @@ ++# Save breakpoints. ++ ++# Copyright (C) 2008, 2009 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++from __future__ import with_statement ++import gdb ++ ++class SavePrefixCommand (gdb.Command): ++ "Prefix command for saving things." ++ ++ def __init__ (self): ++ super (SavePrefixCommand, self).__init__ ("save", ++ gdb.COMMAND_SUPPORT, ++ gdb.COMPLETE_NONE, True) ++ ++class SaveBreakpointsCommand (gdb.Command): ++ """Save the current breakpoints to a file. ++This command takes a single argument, a file name. ++The breakpoints can be restored using the 'source' command.""" ++ ++ def __init__ (self): ++ super (SaveBreakpointsCommand, self).__init__ ("save breakpoints", ++ gdb.COMMAND_SUPPORT, ++ gdb.COMPLETE_FILENAME) ++ ++ def invoke (self, arg, from_tty): ++ self.dont_repeat () ++ bps = gdb.breakpoints () ++ if bps is None: ++ raise RuntimeError, 'No breakpoints to save' ++ with open (arg.strip (), 'w') as f: ++ for bp in bps: ++ print >> f, "break", bp.location, ++ if bp.thread is not None: ++ print >> f, " thread", bp.thread, ++ if bp.condition is not None: ++ print >> f, " if", bp.condition, ++ print >> f ++ if not bp.enabled: ++ print >> f, "disable %d" % bp.number ++ # Note: we don't save the ignore count; there doesn't ++ # seem to be much point. ++ commands = bp.commands ++ if commands is not None: ++ print >> f, "commands" ++ # Note that COMMANDS has a trailing newline. ++ print >> f, commands, ++ print >> f, "end" ++ print >> f ++ ++SavePrefixCommand () ++SaveBreakpointsCommand () +diff --git a/gdb/python/lib/gdb/function/__init__.py b/gdb/python/lib/gdb/function/__init__.py +new file mode 100644 +index 0000000..8b13789 +--- /dev/null ++++ b/gdb/python/lib/gdb/function/__init__.py +@@ -0,0 +1 @@ ++ +diff --git a/gdb/python/lib/gdb/function/caller_is.py b/gdb/python/lib/gdb/function/caller_is.py +new file mode 100644 +index 0000000..2b9c5c7 +--- /dev/null ++++ b/gdb/python/lib/gdb/function/caller_is.py +@@ -0,0 +1,58 @@ ++# Caller-is functions. ++ ++# Copyright (C) 2008 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++import gdb ++import re ++ ++class CallerIs (gdb.Function): ++ """Return True if the calling function's name is equal to a string. ++This function takes one or two arguments. ++The first argument is the name of a function; if the calling function's ++name is equal to this argument, this function returns True. ++The optional second argument tells this function how many stack frames ++to traverse to find the calling function. The default is 1.""" ++ ++ def __init__ (self): ++ super (CallerIs, self).__init__ ("caller_is") ++ ++ def invoke (self, name, nframes = 1): ++ frame = gdb.selected_frame () ++ while nframes > 0: ++ frame = frame.older () ++ nframes = nframes - 1 ++ return frame.name () == name.string () ++ ++class CallerMatches (gdb.Function): ++ """Return True if the calling function's name matches a string. ++This function takes one or two arguments. ++The first argument is a regular expression; if the calling function's ++name is matched by this argument, this function returns True. ++The optional second argument tells this function how many stack frames ++to traverse to find the calling function. The default is 1.""" ++ ++ def __init__ (self): ++ super (CallerMatches, self).__init__ ("caller_matches") ++ ++ def invoke (self, name, nframes = 1): ++ frame = gdb.selected_frame () ++ while nframes > 0: ++ frame = frame.older () ++ nframes = nframes - 1 ++ return re.match (name.string (), frame.name ()) is not None ++ ++CallerIs() ++CallerMatches() +diff --git a/gdb/python/lib/gdb/function/in_scope.py b/gdb/python/lib/gdb/function/in_scope.py +new file mode 100644 +index 0000000..debb3bb +--- /dev/null ++++ b/gdb/python/lib/gdb/function/in_scope.py +@@ -0,0 +1,47 @@ ++# In-scope function. ++ ++# Copyright (C) 2008 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++import gdb ++ ++class InScope (gdb.Function): ++ """Return True if all the given variables or macros are in scope. ++Takes one argument for each variable name to be checked.""" ++ ++ def __init__ (self): ++ super (InScope, self).__init__ ("in_scope") ++ ++ def invoke (self, *vars): ++ if len (vars) == 0: ++ raise TypeError, "in_scope takes at least one argument" ++ ++ # gdb.Value isn't hashable so it can't be put in a map. ++ # Convert to string first. ++ wanted = set (map (lambda x: x.string (), vars)) ++ found = set () ++ block = gdb.selected_frame ().block () ++ while block: ++ for sym in block: ++ if (sym.is_argument or sym.is_constant ++ or sym.is_function or sym.is_variable): ++ if sym.name in wanted: ++ found.add (sym.name) ++ ++ block = block.superblock ++ ++ return wanted == found ++ ++InScope () +diff --git a/gdb/python/lib/gdb/libstdcxx/__init__.py b/gdb/python/lib/gdb/libstdcxx/__init__.py +new file mode 100644 +index 0000000..8b13789 +--- /dev/null ++++ b/gdb/python/lib/gdb/libstdcxx/__init__.py +@@ -0,0 +1 @@ ++ +diff --git a/gdb/python/lib/gdb/libstdcxx/v6/__init__.py b/gdb/python/lib/gdb/libstdcxx/v6/__init__.py +new file mode 100644 +index 0000000..8b13789 +--- /dev/null ++++ b/gdb/python/lib/gdb/libstdcxx/v6/__init__.py +@@ -0,0 +1 @@ ++ +diff --git a/gdb/python/lib/gdb/libstdcxx/v6/hook.in b/gdb/python/lib/gdb/libstdcxx/v6/hook.in +new file mode 100644 +index 0000000..fe7c072 +--- /dev/null ++++ b/gdb/python/lib/gdb/libstdcxx/v6/hook.in +@@ -0,0 +1,27 @@ ++# -*- python -*- ++# Copyright (C) 2009 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++import sys ++import gdb ++ ++# Update module path. ++dir = '@dir@' ++if not dir in sys.path: ++ sys.path.insert(0, dir) ++ ++# Load the pretty-printers. ++from libstdcxx.v6.printers import register_libstdcxx_printers ++register_libstdcxx_printers (gdb.current_objfile ()) +diff --git a/gdb/python/lib/gdb/libstdcxx/v6/printers.py b/gdb/python/lib/gdb/libstdcxx/v6/printers.py +new file mode 100644 +index 0000000..c0dc987 +--- /dev/null ++++ b/gdb/python/lib/gdb/libstdcxx/v6/printers.py +@@ -0,0 +1,647 @@ ++# Pretty-printers for libstc++. ++ ++# Copyright (C) 2008, 2009 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++import gdb ++import itertools ++import re ++ ++class StdPointerPrinter: ++ "Print a smart pointer of some kind" ++ ++ def __init__ (self, typename, val): ++ self.typename = typename ++ self.val = val ++ ++ def to_string (self): ++ return '%s (count %d) %s' % (self.typename, ++ self.val['_M_refcount']['_M_pi']['_M_use_count'], ++ self.val['_M_ptr']) ++ ++class UniquePointerPrinter: ++ "Print a unique_ptr" ++ ++ def __init__ (self, val): ++ self.val = val ++ ++ def to_string (self): ++ return self.val['_M_t'] ++ ++class StdListPrinter: ++ "Print a std::list" ++ ++ class _iterator: ++ def __init__(self, nodetype, head): ++ self.nodetype = nodetype ++ self.base = head['_M_next'] ++ self.head = head.address() ++ self.count = 0 ++ ++ def __iter__(self): ++ return self ++ ++ def next(self): ++ if self.base == self.head: ++ raise StopIteration ++ elt = self.base.cast(self.nodetype).dereference() ++ self.base = elt['_M_next'] ++ count = self.count ++ self.count = self.count + 1 ++ return ('[%d]' % count, elt['_M_data']) ++ ++ def __init__(self, val): ++ self.val = val ++ ++ def children(self): ++ itype = self.val.type().template_argument(0) ++ nodetype = gdb.Type('std::_List_node<%s>' % itype).pointer() ++ return self._iterator(nodetype, self.val['_M_impl']['_M_node']) ++ ++ def to_string(self): ++ if self.val['_M_impl']['_M_node'].address() == self.val['_M_impl']['_M_node']['_M_next']: ++ return 'empty std::list' ++ return 'std::list' ++ ++class StdListIteratorPrinter: ++ "Print std::list::iterator" ++ ++ def __init__(self, val): ++ self.val = val ++ ++ def to_string(self): ++ itype = self.val.type().template_argument(0) ++ nodetype = gdb.Type('std::_List_node<%s>' % itype).pointer() ++ return self.val['_M_node'].cast(nodetype).dereference()['_M_data'] ++ ++class StdSlistPrinter: ++ "Print a __gnu_cxx::slist" ++ ++ class _iterator: ++ def __init__(self, nodetype, head): ++ self.nodetype = nodetype ++ self.base = head['_M_head']['_M_next'] ++ self.count = 0 ++ ++ def __iter__(self): ++ return self ++ ++ def next(self): ++ if self.base == 0: ++ raise StopIteration ++ elt = self.base.cast(self.nodetype).dereference() ++ self.base = elt['_M_next'] ++ count = self.count ++ self.count = self.count + 1 ++ return ('[%d]' % count, elt['_M_data']) ++ ++ def __init__(self, val): ++ self.val = val ++ ++ def children(self): ++ itype = self.val.type().template_argument(0) ++ nodetype = gdb.Type('__gnu_cxx::_Slist_node<%s>' % itype).pointer() ++ return self._iterator(nodetype, self.val) ++ ++ def to_string(self): ++ if self.val['_M_head']['_M_next'] == 0: ++ return 'empty __gnu_cxx::slist' ++ return '__gnu_cxx::slist' ++ ++class StdSlistIteratorPrinter: ++ "Print __gnu_cxx::slist::iterator" ++ ++ def __init__(self, val): ++ self.val = val ++ ++ def to_string(self): ++ itype = self.val.type().template_argument(0) ++ nodetype = gdb.Type('__gnu_cxx::_Slist_node<%s>' % itype).pointer() ++ return self.val['_M_node'].cast(nodetype).dereference()['_M_data'] ++ ++class StdVectorPrinter: ++ "Print a std::vector" ++ ++ class _iterator: ++ def __init__ (self, start, finish): ++ self.item = start ++ self.finish = finish ++ self.count = 0 ++ ++ def __iter__(self): ++ return self ++ ++ def next(self): ++ if self.item == self.finish: ++ raise StopIteration ++ count = self.count ++ self.count = self.count + 1 ++ elt = self.item.dereference() ++ self.item = self.item + 1 ++ return ('[%d]' % count, elt) ++ ++ def __init__(self, val): ++ self.val = val ++ ++ def children(self): ++ return self._iterator(self.val['_M_impl']['_M_start'], ++ self.val['_M_impl']['_M_finish']) ++ ++ def to_string(self): ++ start = self.val['_M_impl']['_M_start'] ++ finish = self.val['_M_impl']['_M_finish'] ++ end = self.val['_M_impl']['_M_end_of_storage'] ++ return ('std::vector of length %d, capacity %d' ++ % (int (finish - start), int (end - start))) ++ ++ def display_hint(self): ++ return 'array' ++ ++class StdVectorIteratorPrinter: ++ "Print std::vector::iterator" ++ ++ def __init__(self, val): ++ self.val = val ++ ++ def to_string(self): ++ return self.val['_M_current'].dereference() ++ ++class StdStackOrQueuePrinter: ++ "Print a std::stack or std::queue" ++ ++ def __init__ (self, typename, val): ++ self.typename = typename ++ self.visualizer = gdb.default_visualizer(val['c']) ++ ++ def children (self): ++ return self.visualizer.children() ++ ++ def to_string (self): ++ return '%s wrapping: %s' % (self.typename, ++ self.visualizer.to_string()) ++ ++ def display_hint (self): ++ if hasattr (self.visualizer, 'display_hint'): ++ return self.visualizer.display_hint () ++ return None ++ ++class RbtreeIterator: ++ def __init__(self, rbtree): ++ self.size = rbtree['_M_t']['_M_impl']['_M_node_count'] ++ self.node = rbtree['_M_t']['_M_impl']['_M_header']['_M_left'] ++ self.count = 0 ++ ++ def __iter__(self): ++ return self ++ ++ def __len__(self): ++ return int (self.size) ++ ++ def next(self): ++ if self.count == self.size: ++ raise StopIteration ++ result = self.node ++ self.count = self.count + 1 ++ if self.count < self.size: ++ # Compute the next node. ++ node = self.node ++ if node.dereference()['_M_right']: ++ node = node.dereference()['_M_right'] ++ while node.dereference()['_M_left']: ++ node = node.dereference()['_M_left'] ++ else: ++ parent = node.dereference()['_M_parent'] ++ while node == parent.dereference()['_M_right']: ++ node = parent ++ parent = parent.dereference()['_M_parent'] ++ if node.dereference()['_M_right'] != parent: ++ node = parent ++ self.node = node ++ return result ++ ++# This is a pretty printer for std::_Rb_tree_iterator (which is ++# std::map::iterator), and has nothing to do with the RbtreeIterator ++# class above. ++class StdRbtreeIteratorPrinter: ++ "Print std::map::iterator" ++ ++ def __init__ (self, val): ++ self.val = val ++ ++ def to_string (self): ++ valuetype = self.val.type().template_argument(0) ++ nodetype = gdb.Type('std::_Rb_tree_node < %s >' % valuetype) ++ nodetype = nodetype.pointer() ++ return self.val.cast(nodetype).dereference()['_M_value_field'] ++ ++ ++class StdMapPrinter: ++ "Print a std::map or std::multimap" ++ ++ # Turn an RbtreeIterator into a pretty-print iterator. ++ class _iter: ++ def __init__(self, rbiter, type): ++ self.rbiter = rbiter ++ self.count = 0 ++ self.type = type ++ ++ def __iter__(self): ++ return self ++ ++ def next(self): ++ if self.count % 2 == 0: ++ n = self.rbiter.next() ++ n = n.cast(self.type).dereference()['_M_value_field'] ++ self.pair = n ++ item = n['first'] ++ else: ++ item = self.pair['second'] ++ result = ('[%d]' % self.count, item) ++ self.count = self.count + 1 ++ return result ++ ++ def __init__ (self, typename, val): ++ self.typename = typename ++ self.val = val ++ self.iter = RbtreeIterator (val) ++ ++ def to_string (self): ++ return '%s with %d elements' % (self.typename, len (self.iter)) ++ ++ def children (self): ++ keytype = self.val.type().template_argument(0).const() ++ valuetype = self.val.type().template_argument(1) ++ nodetype = gdb.Type('std::_Rb_tree_node< std::pair< %s, %s > >' % (keytype, valuetype)) ++ nodetype = nodetype.pointer() ++ return self._iter (self.iter, nodetype) ++ ++ def display_hint (self): ++ return 'map' ++ ++class StdSetPrinter: ++ "Print a std::set or std::multiset" ++ ++ # Turn an RbtreeIterator into a pretty-print iterator. ++ class _iter: ++ def __init__(self, rbiter, type): ++ self.rbiter = rbiter ++ self.count = 0 ++ self.type = type ++ ++ def __iter__(self): ++ return self ++ ++ def next(self): ++ item = self.rbiter.next() ++ item = item.cast(self.type).dereference()['_M_value_field'] ++ # FIXME: this is weird ... what to do? ++ # Maybe a 'set' display hint? ++ result = ('[%d]' % self.count, item) ++ self.count = self.count + 1 ++ return result ++ ++ def __init__ (self, typename, val): ++ self.typename = typename ++ self.val = val ++ self.iter = RbtreeIterator (val) ++ ++ def to_string (self): ++ return '%s with %d elements' % (self.typename, len (self.iter)) ++ ++ def children (self): ++ keytype = self.val.type().template_argument(0) ++ nodetype = gdb.Type('std::_Rb_tree_node< %s >' % keytype).pointer() ++ return self._iter (self.iter, nodetype) ++ ++class StdBitsetPrinter: ++ "Print a std::bitset" ++ ++ def __init__(self, val): ++ self.val = val ++ ++ def to_string (self): ++ # If template_argument handled values, we could print the ++ # size. Or we could use a regexp on the type. ++ return 'std::bitset' ++ ++ def children (self): ++ words = self.val['_M_w'] ++ wtype = words.type() ++ ++ # The _M_w member can be either an unsigned long, or an ++ # array. This depends on the template specialization used. ++ # If it is a single long, convert to a single element list. ++ if wtype.code () == gdb.TYPE_CODE_ARRAY: ++ tsize = wtype.target ().sizeof () ++ else: ++ words = [words] ++ tsize = wtype.sizeof () ++ ++ nwords = wtype.sizeof() / tsize ++ result = [] ++ byte = 0 ++ while byte < nwords: ++ w = words[byte] ++ bit = 0 ++ while w != 0: ++ if (w & 1) != 0: ++ # Another spot where we could use 'set'? ++ result.append(('[%d]' % (byte * tsize * 8 + bit), 1)) ++ bit = bit + 1 ++ w = w >> 1 ++ byte = byte + 1 ++ return result ++ ++class StdDequePrinter: ++ "Print a std::deque" ++ ++ class _iter: ++ def __init__(self, node, start, end, last, buffer_size): ++ self.node = node ++ self.p = start ++ self.end = end ++ self.last = last ++ self.buffer_size = buffer_size ++ self.count = 0 ++ ++ def __iter__(self): ++ return self ++ ++ def next(self): ++ if self.p == self.last: ++ raise StopIteration ++ ++ result = ('[%d]' % self.count, self.p.dereference()) ++ self.count = self.count + 1 ++ ++ # Advance the 'cur' pointer. ++ self.p = self.p + 1 ++ if self.p == self.end: ++ # If we got to the end of this bucket, move to the ++ # next bucket. ++ self.node = self.node + 1 ++ self.p = self.node[0] ++ self.end = self.p + self.buffer_size ++ ++ return result ++ ++ def __init__(self, val): ++ self.val = val ++ self.elttype = val.type().template_argument(0) ++ size = self.elttype.sizeof () ++ if size < 512: ++ self.buffer_size = int (512 / size) ++ else: ++ self.buffer_size = 1 ++ ++ def to_string(self): ++ start = self.val['_M_impl']['_M_start'] ++ end = self.val['_M_impl']['_M_finish'] ++ ++ delta_n = end['_M_node'] - start['_M_node'] - 1 ++ delta_s = start['_M_last'] - start['_M_cur'] ++ delta_e = end['_M_cur'] - end['_M_first'] ++ ++ size = self.buffer_size * delta_n + delta_s + delta_e ++ ++ return 'std::deque with %d elements' % long (size) ++ ++ def children(self): ++ start = self.val['_M_impl']['_M_start'] ++ end = self.val['_M_impl']['_M_finish'] ++ return self._iter(start['_M_node'], start['_M_cur'], start['_M_last'], ++ end['_M_cur'], self.buffer_size) ++ ++ def display_hint (self): ++ return 'array' ++ ++class StdDequeIteratorPrinter: ++ "Print std::deque::iterator" ++ ++ def __init__(self, val): ++ self.val = val ++ ++ def to_string(self): ++ return self.val['_M_cur'].dereference() ++ ++class WideEncoding (gdb.Parameter): ++ """The target wide character set is the encoding used for wchar_t.""" ++ ++ set_doc = "Set the target wide character set." ++ show_doc = "Show the target wide character set." ++ ++ # FIXME: needs a complete method -- but does Parameter support it? ++ def __init__ (self): ++ super (WideEncoding, self).__init__ ("target-wide-charset", ++ gdb.COMMAND_SUPPORT, ++ gdb.PARAM_STRING) ++ # I think this is ok for most glibc locales. ++ self.value = 'UTF-32' ++ ++target_wide_charset = WideEncoding() ++ ++class StdStringPrinter: ++ "Print a std::basic_string of some kind" ++ ++ def __init__(self, encoding, val): ++ self.encoding = encoding ++ self.val = val ++ ++ def to_string(self): ++ # Look up the target encoding as late as possible. ++ encoding = self.encoding ++ if encoding is None: ++ encoding = gdb.parameter('target-charset') ++ elif isinstance(encoding, WideEncoding): ++ encoding = encoding.value ++ return self.val['_M_dataplus']['_M_p'].string(encoding) ++ ++ def display_hint (self): ++ return 'string' ++ ++class Tr1HashtableIterator: ++ def __init__ (self, hash): ++ self.count = 0 ++ self.n_buckets = hash['_M_element_count'] ++ if self.n_buckets == 0: ++ self.node = False ++ else: ++ self.bucket = hash['_M_buckets'] ++ self.node = self.bucket[0] ++ self.update () ++ ++ def __iter__ (self): ++ return self ++ ++ def update (self): ++ # If we advanced off the end of the chain, move to the next ++ # bucket. ++ while self.node == 0: ++ self.bucket = self.bucket + 1 ++ self.node = self.bucket[0] ++ ++ # If we advanced off the end of the bucket array, then ++ # we're done. ++ if self.count == self.n_buckets: ++ self.node = False ++ else: ++ self.count = self.count + 1 ++ ++ def next (self): ++ if not self.node: ++ raise StopIteration ++ result = self.node.dereference()['_M_v'] ++ self.node = self.node.dereference()['_M_next'] ++ self.update () ++ return result ++ ++class Tr1UnorderedSetPrinter: ++ "Print a tr1::unordered_set" ++ ++ def __init__ (self, typename, val): ++ self.typename = typename ++ self.val = val ++ ++ def to_string (self): ++ return '%s with %d elements' % (self.typename, self.val['_M_element_count']) ++ ++ @staticmethod ++ def format_count (i): ++ return '[%d]' % i ++ ++ def children (self): ++ counter = itertools.imap (self.format_count, itertools.count()) ++ return itertools.izip (counter, Tr1HashtableIterator (self.val)) ++ ++class Tr1UnorderedMapPrinter: ++ "Print a tr1::unordered_map" ++ ++ def __init__ (self, typename, val): ++ self.typename = typename ++ self.val = val ++ ++ def to_string (self): ++ return '%s with %d elements' % (self.typename, self.val['_M_element_count']) ++ ++ @staticmethod ++ def flatten (list): ++ for elt in list: ++ for i in elt: ++ yield i ++ ++ @staticmethod ++ def format_one (elt): ++ return (elt['first'], elt['second']) ++ ++ @staticmethod ++ def format_count (i): ++ return '[%d]' % i ++ ++ def children (self): ++ counter = itertools.imap (self.format_count, itertools.count()) ++ # Map over the hash table and flatten the result. ++ data = self.flatten (itertools.imap (self.format_one, Tr1HashtableIterator (self.val))) ++ # Zip the two iterators together. ++ return itertools.izip (counter, data) ++ ++ def display_hint (self): ++ return 'map' ++ ++def register_libstdcxx_printers (obj): ++ "Register libstdc++ pretty-printers with objfile Obj." ++ ++ if obj == None: ++ obj = gdb ++ ++ obj.pretty_printers.append (lookup_function) ++ ++def lookup_function (val): ++ "Look-up and return a pretty-printer that can print val." ++ ++ # Get the type. ++ type = val.type (); ++ ++ # If it points to a reference, get the reference. ++ if type.code () == gdb.TYPE_CODE_REF: ++ type = type.target () ++ ++ # Get the unqualified type, stripped of typedefs. ++ type = type.unqualified ().strip_typedefs () ++ ++ # Get the type name. ++ typename = type.tag () ++ if typename == None: ++ return None ++ ++ # Iterate over local dictionary of types to determine ++ # if a printer is registered for that type. Return an ++ # instantiation of the printer if found. ++ for function in pretty_printers_dict: ++ if function.search (typename): ++ return pretty_printers_dict[function] (val) ++ ++ # Cannot find a pretty printer. Return None. ++ return None ++ ++def build_libstdcxx_dictionary (): ++ # libstdc++ objects requiring pretty-printing. ++ # In order from: ++ # http://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/a01847.html ++ pretty_printers_dict[re.compile('^std::basic_string$')] = lambda val: StdStringPrinter(None, val) ++ pretty_printers_dict[re.compile('^std::basic_string$')] = lambda val: StdStringPrinter(target_wide_charset, val) ++ pretty_printers_dict[re.compile('^std::basic_string$')] = lambda val: StdStringPrinter('UTF-16', val) ++ pretty_printers_dict[re.compile('^std::basic_string$')] = lambda val: StdStringPrinter('UTF-32', val) ++ pretty_printers_dict[re.compile('^std::bitset<.*>$')] = StdBitsetPrinter ++ pretty_printers_dict[re.compile('^std::deque<.*>$')] = StdDequePrinter ++ pretty_printers_dict[re.compile('^std::list<.*>$')] = StdListPrinter ++ pretty_printers_dict[re.compile('^std::map<.*>$')] = lambda val: StdMapPrinter("std::map", val) ++ pretty_printers_dict[re.compile('^std::multimap<.*>$')] = lambda val: StdMapPrinter("std::multimap", val) ++ pretty_printers_dict[re.compile('^std::multiset<.*>$')] = lambda val: StdSetPrinter("std::multiset", val) ++ pretty_printers_dict[re.compile('^std::priority_queue<.*>$')] = lambda val: StdStackOrQueuePrinter("std::priority_queue", val) ++ pretty_printers_dict[re.compile('^std::queue<.*>$')] = lambda val: StdStackOrQueuePrinter("std::queue", val) ++ pretty_printers_dict[re.compile('^std::set<.*>$')] = lambda val: StdSetPrinter("std::set", val) ++ pretty_printers_dict[re.compile('^std::stack<.*>$')] = lambda val: StdStackOrQueuePrinter("std::stack", val) ++ pretty_printers_dict[re.compile('^std::unique_ptr<.*>$')] = UniquePointerPrinter ++ pretty_printers_dict[re.compile('^std::vector<.*>$')] = StdVectorPrinter ++ # vector ++ ++ # These are the C++0x printers. They also exist in the standard namespace. ++ # For array - the default GDB pretty-printer seems reasonable. ++ pretty_printers_dict[re.compile('^std::(tr1::)?shared_ptr<.*>$')] = lambda val: StdPointerPrinter ('std::shared_ptr', val) ++ pretty_printers_dict[re.compile('^std::(tr1::)?weak_ptr<.*>$')] = lambda val: StdPointerPrinter ('std::weak_ptr', val) ++ pretty_printers_dict[re.compile('^std::(tr1::)?unordered_map<.*>$')] = lambda val: Tr1UnorderedMapPrinter ('std::tr1::unordered_map', val) ++ pretty_printers_dict[re.compile('^std::(tr1::)?unordered_set<.*>$')] = lambda val: Tr1UnorderedSetPrinter ('std::tr1::unordered_set', val) ++ pretty_printers_dict[re.compile('^std::(tr1::)?unordered_multimap<.*>$')] = lambda val: Tr1UnorderedMapPrinter ('std::tr1::unordered_multimap', val) ++ pretty_printers_dict[re.compile('^std::(tr1::)?unordered_multiset<.*>$')] = lambda val: Tr1UnorderedSetPrinter ('std::tr1::unordered_multiset', val) ++ ++ ++ # Extensions. ++ pretty_printers_dict[re.compile('^__gnu_cxx::slist<.*>$')] = StdSlistPrinter ++ ++ if True: ++ # These shouldn't be necessary, if GDB "print *i" worked. ++ # But it often doesn't, so here they are. ++ pretty_printers_dict[re.compile('^std::_List_iterator<.*>$')] = lambda val: StdListIteratorPrinter(val) ++ pretty_printers_dict[re.compile('^std::_List_const_iterator<.*>$')] = lambda val: StdListIteratorPrinter(val) ++ pretty_printers_dict[re.compile('^std::_Rb_tree_iterator<.*>$')] = lambda val: StdRbtreeIteratorPrinter(val) ++ pretty_printers_dict[re.compile('^std::_Rb_tree_const_iterator<.*>$')] = lambda val: StdRbtreeIteratorPrinter(val) ++ pretty_printers_dict[re.compile('^std::_Deque_iterator<.*>$')] = lambda val: StdDequeIteratorPrinter(val) ++ pretty_printers_dict[re.compile('^std::_Deque_const_iterator<.*>$')] = lambda val: StdDequeIteratorPrinter(val) ++ pretty_printers_dict[re.compile('^__gnu_cxx::__normal_iterator<.*>$')] = lambda val: StdVectorIteratorPrinter(val) ++ pretty_printers_dict[re.compile('^__gnu_cxx::_Slist_iterator<.*>$')] = lambda val: StdSlistIteratorPrinter(val) ++ ++pretty_printers_dict = {} ++ ++build_libstdcxx_dictionary () +diff --git a/gdb/python/python-block.c b/gdb/python/python-block.c +new file mode 100644 +index 0000000..8019e9d +--- /dev/null ++++ b/gdb/python/python-block.c +@@ -0,0 +1,265 @@ ++/* Python interface to blocks. ++ ++ Copyright (C) 2008 Free Software Foundation, Inc. ++ ++ This file is part of GDB. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++#include "defs.h" ++#include "block.h" ++#include "dictionary.h" ++#include "symtab.h" ++#include "python-internal.h" ++ ++typedef struct { ++ PyObject_HEAD ++ struct block *block; ++} block_object; ++ ++typedef struct { ++ PyObject_HEAD ++ struct dictionary *dict; ++ struct dict_iterator iter; ++ int initialized_p; ++} block_syms_iterator_object; ++ ++static PyTypeObject block_syms_iterator_object_type; ++ ++static PyObject * ++blpy_iter (PyObject *self) ++{ ++ block_syms_iterator_object *block_iter_obj; ++ ++ block_iter_obj = PyObject_New (block_syms_iterator_object, ++ &block_syms_iterator_object_type); ++ if (block_iter_obj == NULL) ++ { ++ PyErr_SetString (PyExc_MemoryError, ++ "Could not allocate iterator object."); ++ return NULL; ++ } ++ ++ block_iter_obj->dict = BLOCK_DICT (((block_object *) self)->block); ++ block_iter_obj->initialized_p = 0; ++ ++ return (PyObject *) block_iter_obj; ++} ++ ++static PyObject * ++blpy_get_start (PyObject *self, void *closure) ++{ ++ block_object *self_block = (block_object *) self; ++ ++ return PyLong_FromUnsignedLongLong (BLOCK_START (self_block->block)); ++} ++ ++static PyObject * ++blpy_get_end (PyObject *self, void *closure) ++{ ++ block_object *self_block = (block_object *) self; ++ ++ return PyLong_FromUnsignedLongLong (BLOCK_END (self_block->block)); ++} ++ ++static PyObject * ++blpy_get_function (PyObject *self, void *closure) ++{ ++ block_object *self_block = (block_object *) self; ++ struct symbol *sym; ++ ++ sym = BLOCK_FUNCTION (self_block->block); ++ if (sym) ++ return symbol_to_symbol_object (sym); ++ ++ Py_RETURN_NONE; ++} ++ ++static PyObject * ++blpy_get_superblock (PyObject *self, void *closure) ++{ ++ block_object *self_block = (block_object *) self; ++ struct block *block; ++ ++ block = BLOCK_SUPERBLOCK (self_block->block); ++ if (block) ++ return block_to_block_object (block); ++ ++ Py_RETURN_NONE; ++} ++ ++PyObject * ++block_to_block_object (struct block *block) ++{ ++ block_object *block_obj; ++ ++ block_obj = PyObject_New (block_object, &block_object_type); ++ if (block_obj == NULL) ++ { ++ PyErr_SetString (PyExc_MemoryError, "Could not allocate block object."); ++ return NULL; ++ } ++ ++ block_obj->block = block; ++ ++ return (PyObject *) block_obj; ++} ++ ++struct block * ++block_object_to_block (PyObject *obj) ++{ ++ if (! PyObject_TypeCheck (obj, &block_object_type)) ++ return NULL; ++ return ((block_object *) obj)->block; ++} ++ ++static PyObject * ++blpy_block_syms_iter (PyObject *self) ++{ ++ return self; ++} ++ ++static PyObject * ++blpy_block_syms_iternext (PyObject *self) ++{ ++ block_syms_iterator_object *iter_obj = (block_syms_iterator_object *) self; ++ struct symbol *sym; ++ ++ if (!iter_obj->initialized_p) ++ { ++ sym = dict_iterator_first (iter_obj->dict, &(iter_obj->iter)); ++ iter_obj->initialized_p = 1; ++ } ++ else ++ sym = dict_iterator_next (&(iter_obj->iter)); ++ ++ return (sym == NULL)? NULL : symbol_to_symbol_object (sym); ++} ++ ++/* Return the innermost lexical block containing the specified pc value, ++ or 0 if there is none. */ ++ ++PyObject * ++gdbpy_block_for_pc (PyObject *self, PyObject *args) ++{ ++ unsigned PY_LONG_LONG pc; ++ struct block *block; ++ PyObject *sym_obj; ++ ++ if (!PyArg_ParseTuple (args, "K", &pc)) ++ return NULL; ++ ++ block = block_for_pc (pc); ++ if (block) ++ return block_to_block_object (block); ++ ++ Py_RETURN_NONE; ++} ++ ++void ++gdbpy_initialize_blocks (void) ++{ ++ block_object_type.tp_new = PyType_GenericNew; ++ if (PyType_Ready (&block_object_type) < 0) ++ return; ++ ++ block_syms_iterator_object_type.tp_new = PyType_GenericNew; ++ if (PyType_Ready (&block_syms_iterator_object_type) < 0) ++ return; ++ ++ Py_INCREF (&block_object_type); ++ PyModule_AddObject (gdb_module, "Block", (PyObject *) &block_object_type); ++ ++ Py_INCREF (&block_syms_iterator_object_type); ++ PyModule_AddObject (gdb_module, "BlockIterator", ++ (PyObject *) &block_syms_iterator_object_type); ++} ++ ++ ++ ++static PyGetSetDef block_object_getset[] = { ++ { "start", blpy_get_start, NULL, "Start address of the block.", NULL }, ++ { "end", blpy_get_end, NULL, "End address of the block.", NULL }, ++ { "function", blpy_get_function, NULL, ++ "Symbol that names the block, or None.", NULL }, ++ { "superblock", blpy_get_superblock, NULL, ++ "Block containing the block, or None.", NULL }, ++ { NULL } /* Sentinel */ ++}; ++ ++PyTypeObject block_object_type = { ++ PyObject_HEAD_INIT (NULL) ++ 0, /*ob_size*/ ++ "gdb.Block", /*tp_name*/ ++ sizeof (block_object), /*tp_basicsize*/ ++ 0, /*tp_itemsize*/ ++ 0, /*tp_dealloc*/ ++ 0, /*tp_print*/ ++ 0, /*tp_getattr*/ ++ 0, /*tp_setattr*/ ++ 0, /*tp_compare*/ ++ 0, /*tp_repr*/ ++ 0, /*tp_as_number*/ ++ 0, /*tp_as_sequence*/ ++ 0, /*tp_as_mapping*/ ++ 0, /*tp_hash */ ++ 0, /*tp_call*/ ++ 0, /*tp_str*/ ++ 0, /*tp_getattro*/ ++ 0, /*tp_setattro*/ ++ 0, /*tp_as_buffer*/ ++ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER, /*tp_flags*/ ++ "GDB block object", /* tp_doc */ ++ 0, /* tp_traverse */ ++ 0, /* tp_clear */ ++ 0, /* tp_richcompare */ ++ 0, /* tp_weaklistoffset */ ++ blpy_iter, /* tp_iter */ ++ 0, /* tp_iternext */ ++ 0, /* tp_methods */ ++ 0, /* tp_members */ ++ block_object_getset /* tp_getset */ ++}; ++ ++static PyTypeObject block_syms_iterator_object_type = { ++ PyObject_HEAD_INIT (NULL) ++ 0, /*ob_size*/ ++ "gdb.BlockIterator", /*tp_name*/ ++ sizeof (block_syms_iterator_object), /*tp_basicsize*/ ++ 0, /*tp_itemsize*/ ++ 0, /*tp_dealloc*/ ++ 0, /*tp_print*/ ++ 0, /*tp_getattr*/ ++ 0, /*tp_setattr*/ ++ 0, /*tp_compare*/ ++ 0, /*tp_repr*/ ++ 0, /*tp_as_number*/ ++ 0, /*tp_as_sequence*/ ++ 0, /*tp_as_mapping*/ ++ 0, /*tp_hash */ ++ 0, /*tp_call*/ ++ 0, /*tp_str*/ ++ 0, /*tp_getattro*/ ++ 0, /*tp_setattro*/ ++ 0, /*tp_as_buffer*/ ++ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER, /*tp_flags*/ ++ "GDB block syms iterator object", /* tp_doc */ ++ 0, /* tp_traverse */ ++ 0, /* tp_clear */ ++ 0, /* tp_richcompare */ ++ 0, /* tp_weaklistoffset */ ++ blpy_block_syms_iter, /* tp_iter */ ++ blpy_block_syms_iternext, /* tp_iternext */ ++ 0 /* tp_methods */ ++}; +diff --git a/gdb/python/python-breakpoint.c b/gdb/python/python-breakpoint.c +new file mode 100644 +index 0000000..ec80419 +--- /dev/null ++++ b/gdb/python/python-breakpoint.c +@@ -0,0 +1,665 @@ ++/* Python interface to breakpoints ++ ++ Copyright (C) 2008, 2009 Free Software Foundation, Inc. ++ ++ This file is part of GDB. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++#include "defs.h" ++#include "value.h" ++#include "exceptions.h" ++#include "python-internal.h" ++#include "charset.h" ++#include "breakpoint.h" ++#include "gdbcmd.h" ++#include "gdbthread.h" ++#include "observer.h" ++ ++ ++/* From breakpoint.c. */ ++extern struct breakpoint *breakpoint_chain; ++ ++ ++typedef struct breakpoint_object breakpoint_object; ++ ++static PyTypeObject breakpoint_object_type; ++ ++/* A dynamically allocated vector of breakpoint objects. Each ++ breakpoint has a number. A breakpoint is valid if its slot in this ++ vector is non-null. When a breakpoint is deleted, we drop our ++ reference to it and zero its slot; this is how we let the Python ++ object have a lifetime which is independent from that of the gdb ++ breakpoint. */ ++static breakpoint_object **bppy_breakpoints; ++ ++/* Number of slots in bppy_breakpoints. */ ++static int bppy_slots; ++ ++/* Number of live breakpoints. */ ++static int bppy_live; ++ ++/* Variables used to pass information between the Breakpoint ++ constructor and the breakpoint-created hook function. */ ++static breakpoint_object *bppy_pending_object; ++ ++struct breakpoint_object ++{ ++ PyObject_HEAD ++ ++ /* The breakpoint number according to gdb. */ ++ int number; ++ ++ /* The gdb breakpoint object, or NULL if the breakpoint has been ++ deleted. */ ++ struct breakpoint *bp; ++}; ++ ++/* Evaluate to true if the breakpoint NUM is valid, false otherwise. */ ++#define BPPY_VALID_P(Num) \ ++ ((Num) >= 0 \ ++ && (Num) < bppy_slots \ ++ && bppy_breakpoints[Num] != NULL) ++ ++/* Require that BREAKPOINT be a valid breakpoint ID; throw a Python ++ exception if it is invalid. */ ++#define BPPY_REQUIRE_VALID(Breakpoint) \ ++ do { \ ++ if (! BPPY_VALID_P ((Breakpoint)->number)) \ ++ return PyErr_Format (PyExc_RuntimeError, "breakpoint %d is invalid", \ ++ (Breakpoint)->number); \ ++ } while (0) ++ ++/* Require that BREAKPOINT be a valid breakpoint ID; throw a Python ++ exception if it is invalid. This macro is for use in setter functions. */ ++#define BPPY_SET_REQUIRE_VALID(Breakpoint) \ ++ do { \ ++ if (! BPPY_VALID_P ((Breakpoint)->number)) \ ++ { \ ++ PyErr_Format (PyExc_RuntimeError, "breakpoint %d is invalid", \ ++ (Breakpoint)->number); \ ++ return -1; \ ++ } \ ++ } while (0) ++ ++/* Python function which checks the validity of a breakpoint object. */ ++static PyObject * ++bppy_is_valid (PyObject *self, PyObject *args) ++{ ++ if (((breakpoint_object *) self)->bp) ++ Py_RETURN_TRUE; ++ Py_RETURN_FALSE; ++} ++ ++/* Python function to test whether or not the breakpoint is enabled. */ ++static PyObject * ++bppy_get_enabled (PyObject *self, void *closure) ++{ ++ if (! ((breakpoint_object *) self)->bp) ++ Py_RETURN_FALSE; ++ /* Not clear what we really want here. */ ++ if (((breakpoint_object *) self)->bp->enable_state == bp_enabled) ++ Py_RETURN_TRUE; ++ Py_RETURN_FALSE; ++} ++ ++/* Python function to test whether or not the breakpoint is silent. */ ++static PyObject * ++bppy_get_silent (PyObject *self, void *closure) ++{ ++ BPPY_REQUIRE_VALID ((breakpoint_object *) self); ++ if (((breakpoint_object *) self)->bp->silent) ++ Py_RETURN_TRUE; ++ Py_RETURN_FALSE; ++} ++ ++/* Python function to set the enabled state of a breakpoint. */ ++static int ++bppy_set_enabled (PyObject *self, PyObject *newvalue, void *closure) ++{ ++ breakpoint_object *self_bp = (breakpoint_object *) self; ++ int cmp; ++ ++ BPPY_SET_REQUIRE_VALID (self_bp); ++ ++ if (newvalue == NULL) ++ { ++ PyErr_SetString (PyExc_TypeError, "cannot delete `enabled' attribute"); ++ return -1; ++ } ++ else if (! PyBool_Check (newvalue)) ++ { ++ PyErr_SetString (PyExc_TypeError, ++ "the value of `enabled' must be a boolean"); ++ return -1; ++ } ++ ++ cmp = PyObject_IsTrue (newvalue); ++ if (cmp < 0) ++ return -1; ++ else if (cmp == 1) ++ enable_breakpoint (self_bp->bp); ++ else ++ disable_breakpoint (self_bp->bp); ++ return 0; ++} ++ ++/* Python function to set the 'silent' state of a breakpoint. */ ++static int ++bppy_set_silent (PyObject *self, PyObject *newvalue, void *closure) ++{ ++ breakpoint_object *self_bp = (breakpoint_object *) self; ++ int cmp; ++ ++ BPPY_SET_REQUIRE_VALID (self_bp); ++ ++ if (newvalue == NULL) ++ { ++ PyErr_SetString (PyExc_TypeError, "cannot delete `silent' attribute"); ++ return -1; ++ } ++ else if (! PyBool_Check (newvalue)) ++ { ++ PyErr_SetString (PyExc_TypeError, ++ "the value of `silent' must be a boolean"); ++ return -1; ++ } ++ ++ cmp = PyObject_IsTrue (newvalue); ++ if (cmp < 0) ++ return -1; ++ else ++ self_bp->bp->silent = cmp; ++ ++ return 0; ++} ++ ++/* Python function to set the thread of a breakpoint. */ ++static int ++bppy_set_thread (PyObject *self, PyObject *newvalue, void *closure) ++{ ++ breakpoint_object *self_bp = (breakpoint_object *) self; ++ int id; ++ ++ BPPY_SET_REQUIRE_VALID (self_bp); ++ ++ if (newvalue == NULL) ++ { ++ PyErr_SetString (PyExc_TypeError, "cannot delete `thread' attribute"); ++ return -1; ++ } ++ else if (PyInt_Check (newvalue)) ++ { ++ id = (int) PyInt_AsLong (newvalue); ++ if (! valid_thread_id (id)) ++ { ++ PyErr_SetString (PyExc_RuntimeError, "invalid thread id"); ++ return -1; ++ } ++ } ++ else if (newvalue == Py_None) ++ id = -1; ++ else ++ { ++ PyErr_SetString (PyExc_TypeError, ++ "the value of `thread' must be an integer or None"); ++ return -1; ++ } ++ ++ self_bp->bp->thread = id; ++ ++ return 0; ++} ++ ++/* Python function to set the ignore count of a breakpoint. */ ++static int ++bppy_set_ignore_count (PyObject *self, PyObject *newvalue, void *closure) ++{ ++ breakpoint_object *self_bp = (breakpoint_object *) self; ++ long value; ++ ++ BPPY_SET_REQUIRE_VALID (self_bp); ++ ++ if (newvalue == NULL) ++ { ++ PyErr_SetString (PyExc_TypeError, ++ "cannot delete `ignore_count' attribute"); ++ return -1; ++ } ++ else if (! PyInt_Check (newvalue)) ++ { ++ PyErr_SetString (PyExc_TypeError, ++ "the value of `ignore_count' must be an integer"); ++ return -1; ++ } ++ ++ value = PyInt_AsLong (newvalue); ++ if (value < 0) ++ value = 0; ++ set_ignore_count (self_bp->number, (int) value, 0); ++ ++ return 0; ++} ++ ++/* Python function to set the hit count of a breakpoint. */ ++static int ++bppy_set_hit_count (PyObject *self, PyObject *newvalue, void *closure) ++{ ++ breakpoint_object *self_bp = (breakpoint_object *) self; ++ ++ BPPY_SET_REQUIRE_VALID (self_bp); ++ ++ if (newvalue == NULL) ++ { ++ PyErr_SetString (PyExc_TypeError, "cannot delete `hit_count' attribute"); ++ return -1; ++ } ++ else if (! PyInt_Check (newvalue) || PyInt_AsLong (newvalue) != 0) ++ { ++ PyErr_SetString (PyExc_AttributeError, ++ "the value of `hit_count' must be zero"); ++ return -1; ++ } ++ ++ self_bp->bp->hit_count = 0; ++ ++ return 0; ++} ++ ++/* Python function to get the location of a breakpoint. */ ++static PyObject * ++bppy_get_location (PyObject *self, void *closure) ++{ ++ char *str; ++ ++ BPPY_REQUIRE_VALID ((breakpoint_object *) self); ++ str = ((breakpoint_object *) self)->bp->addr_string; ++ /* FIXME: watchpoints? tracepoints? */ ++ if (! str) ++ str = ""; ++ return PyString_Decode (str, strlen (str), host_charset (), NULL); ++} ++ ++/* Python function to get the condition expression of a breakpoint. */ ++static PyObject * ++bppy_get_condition (PyObject *self, void *closure) ++{ ++ char *str; ++ BPPY_REQUIRE_VALID ((breakpoint_object *) self); ++ ++ str = ((breakpoint_object *) self)->bp->cond_string; ++ if (! str) ++ Py_RETURN_NONE; ++ return PyString_Decode (str, strlen (str), host_charset (), NULL); ++} ++ ++static int ++bppy_set_condition (PyObject *self, PyObject *newvalue, void *closure) ++{ ++ char *exp; ++ breakpoint_object *self_bp = (breakpoint_object *) self; ++ volatile struct gdb_exception except; ++ ++ BPPY_SET_REQUIRE_VALID (self_bp); ++ ++ if (newvalue == NULL) ++ { ++ PyErr_SetString (PyExc_TypeError, "cannot delete `condition' attribute"); ++ return -1; ++ } ++ else if (newvalue == Py_None) ++ exp = ""; ++ else ++ { ++ exp = python_string_to_host_string (newvalue); ++ if (exp == NULL) ++ return -1; ++ } ++ ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ set_breakpoint_condition (self_bp->bp, exp, 0); ++ } ++ GDB_PY_SET_HANDLE_EXCEPTION (except); ++ ++ return 0; ++} ++ ++/* Python function to get the commands attached to a breakpoint. */ ++static PyObject * ++bppy_get_commands (PyObject *self, void *closure) ++{ ++ breakpoint_object *self_bp = (breakpoint_object *) self; ++ long length; ++ volatile struct gdb_exception except; ++ struct ui_file *string_file; ++ struct cleanup *chain; ++ PyObject *result; ++ char *cmdstr; ++ ++ BPPY_REQUIRE_VALID (self_bp); ++ ++ if (! self_bp->bp->commands) ++ Py_RETURN_NONE; ++ ++ string_file = mem_fileopen (); ++ chain = make_cleanup_ui_file_delete (string_file); ++ ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ /* FIXME: this can fail. Maybe we need to be making a new ++ ui_out object here? */ ++ ui_out_redirect (uiout, string_file); ++ print_command_lines (uiout, self_bp->bp->commands, 0); ++ ui_out_redirect (uiout, NULL); ++ } ++ cmdstr = ui_file_xstrdup (string_file, &length); ++ GDB_PY_HANDLE_EXCEPTION (except); ++ ++ result = PyString_Decode (cmdstr, strlen (cmdstr), host_charset (), NULL); ++ do_cleanups (chain); ++ xfree (cmdstr); ++ return result; ++} ++ ++/* Python function to get the breakpoint's number. */ ++static PyObject * ++bppy_get_number (PyObject *self, void *closure) ++{ ++ breakpoint_object *self_bp = (breakpoint_object *) self; ++ ++ BPPY_REQUIRE_VALID (self_bp); ++ ++ return PyInt_FromLong (self_bp->number); ++} ++ ++/* Python function to get the breakpoint's thread ID. */ ++static PyObject * ++bppy_get_thread (PyObject *self, void *closure) ++{ ++ breakpoint_object *self_bp = (breakpoint_object *) self; ++ ++ BPPY_REQUIRE_VALID (self_bp); ++ ++ if (self_bp->bp->thread == -1) ++ Py_RETURN_NONE; ++ ++ return PyInt_FromLong (self_bp->bp->thread); ++} ++ ++/* Python function to get the breakpoint's hit count. */ ++static PyObject * ++bppy_get_hit_count (PyObject *self, void *closure) ++{ ++ breakpoint_object *self_bp = (breakpoint_object *) self; ++ ++ BPPY_REQUIRE_VALID (self_bp); ++ ++ return PyInt_FromLong (self_bp->bp->hit_count); ++} ++ ++/* Python function to get the breakpoint's ignore count. */ ++static PyObject * ++bppy_get_ignore_count (PyObject *self, void *closure) ++{ ++ breakpoint_object *self_bp = (breakpoint_object *) self; ++ ++ BPPY_REQUIRE_VALID (self_bp); ++ ++ return PyInt_FromLong (self_bp->bp->ignore_count); ++} ++ ++/* Python function to create a new breakpoint. */ ++static PyObject * ++bppy_new (PyTypeObject *subtype, PyObject *args, PyObject *kwargs) ++{ ++ PyObject *result; ++ char *spec; ++ volatile struct gdb_exception except; ++ ++ /* FIXME: allow condition, thread, temporary, ... ? */ ++ if (! PyArg_ParseTuple (args, "s", &spec)) ++ return NULL; ++ result = subtype->tp_alloc (subtype, 0); ++ if (! result) ++ return NULL; ++ bppy_pending_object = (breakpoint_object *) result; ++ bppy_pending_object->number = -1; ++ bppy_pending_object->bp = NULL; ++ ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ set_breakpoint (spec, NULL, 0, 0, -1, 0, AUTO_BOOLEAN_TRUE, ++ 1 /*enabled*/); ++ } ++ if (except.reason < 0) ++ { ++ subtype->tp_free (result); ++ return PyErr_Format (except.reason == RETURN_QUIT ++ ? PyExc_KeyboardInterrupt : PyExc_RuntimeError, ++ "%s", except.message); ++ } ++ ++ BPPY_REQUIRE_VALID ((breakpoint_object *) result); ++ return result; ++} ++ ++ ++ ++/* Static function to return a tuple holding all breakpoints. */ ++ ++PyObject * ++gdbpy_breakpoints (PyObject *self, PyObject *args) ++{ ++ PyObject *result; ++ ++ if (bppy_live == 0) ++ Py_RETURN_NONE; ++ ++ result = PyTuple_New (bppy_live); ++ if (result) ++ { ++ int i, out = 0; ++ for (i = 0; out < bppy_live; ++i) ++ { ++ if (! bppy_breakpoints[i]) ++ continue; ++ Py_INCREF (bppy_breakpoints[i]); ++ PyTuple_SetItem (result, out, (PyObject *) bppy_breakpoints[i]); ++ ++out; ++ } ++ } ++ return result; ++} ++ ++ ++ ++/* Event callback functions. */ ++ ++/* Callback that is used when a breakpoint is created. This function ++ will create a new Python breakpoint object. */ ++static void ++gdbpy_breakpoint_created (int num) ++{ ++ breakpoint_object *newbp; ++ struct breakpoint *bp; ++ PyGILState_STATE state; ++ ++ if (num < 0) ++ return; ++ ++ for (bp = breakpoint_chain; bp; bp = bp->next) ++ if (bp->number == num) ++ break; ++ if (! bp) ++ return; ++ ++ if (num >= bppy_slots) ++ { ++ int old = bppy_slots; ++ bppy_slots = bppy_slots * 2 + 10; ++ bppy_breakpoints ++ = (breakpoint_object **) xrealloc (bppy_breakpoints, ++ (bppy_slots ++ * sizeof (breakpoint_object *))); ++ memset (&bppy_breakpoints[old], 0, ++ (bppy_slots - old) * sizeof (PyObject *)); ++ } ++ ++ ++bppy_live; ++ ++ state = PyGILState_Ensure (); ++ ++ if (bppy_pending_object) ++ { ++ newbp = bppy_pending_object; ++ bppy_pending_object = NULL; ++ } ++ else ++ newbp = PyObject_New (breakpoint_object, &breakpoint_object_type); ++ if (newbp) ++ { ++ PyObject *hookfn; ++ ++ newbp->number = num; ++ newbp->bp = bp; ++ bppy_breakpoints[num] = newbp; ++ ++ hookfn = gdbpy_get_hook_function ("new_breakpoint"); ++ if (hookfn) ++ { ++ PyObject *result; ++ result = PyObject_CallFunctionObjArgs (hookfn, newbp, NULL); ++ if (result) ++ { ++ Py_DECREF (result); ++ } ++ Py_DECREF (hookfn); ++ } ++ } ++ ++ /* Just ignore errors here. */ ++ PyErr_Clear (); ++ ++ PyGILState_Release (state); ++} ++ ++/* Callback that is used when a breakpoint is deleted. This will ++ invalidate the corresponding Python object. */ ++static void ++gdbpy_breakpoint_deleted (int num) ++{ ++ PyGILState_STATE state; ++ ++ state = PyGILState_Ensure (); ++ if (BPPY_VALID_P (num)) ++ { ++ bppy_breakpoints[num]->bp = NULL; ++ Py_DECREF (bppy_breakpoints[num]); ++ bppy_breakpoints[num] = NULL; ++ --bppy_live; ++ } ++ PyGILState_Release (state); ++} ++ ++ ++ ++/* Initialize the Python breakpoint code. */ ++void ++gdbpy_initialize_breakpoints (void) ++{ ++ breakpoint_object_type.tp_new = bppy_new; ++ if (PyType_Ready (&breakpoint_object_type) < 0) ++ return; ++ ++ Py_INCREF (&breakpoint_object_type); ++ PyModule_AddObject (gdb_module, "Breakpoint", ++ (PyObject *) &breakpoint_object_type); ++ ++ observer_attach_breakpoint_created (gdbpy_breakpoint_created); ++ observer_attach_breakpoint_deleted (gdbpy_breakpoint_deleted); ++} ++ ++ ++ ++static PyGetSetDef breakpoint_object_getset[] = { ++ { "enabled", bppy_get_enabled, bppy_set_enabled, ++ "Boolean telling whether the breakpoint is enabled.", NULL }, ++ { "silent", bppy_get_silent, bppy_set_silent, ++ "Boolean telling whether the breakpoint is silent.", NULL }, ++ { "thread", bppy_get_thread, bppy_set_thread, ++ "Thread ID for the breakpoint.\n\ ++If the value is a thread ID (integer), then this is a thread-specific breakpoint.\n\ ++If the value is None, then this breakpoint not thread-specific.\n\ ++No other type of value can be used.", NULL }, ++ { "ignore_count", bppy_get_ignore_count, bppy_set_ignore_count, ++ "Number of times this breakpoint should be automatically continued.", ++ NULL }, ++ { "number", bppy_get_number, NULL, ++ "Breakpoint's number assigned by GDB.", NULL }, ++ { "hit_count", bppy_get_hit_count, bppy_set_hit_count, ++ "Number of times the breakpoint has been hit.\n\ ++Can be set to zero to clear the count. No other value is valid\n\ ++when setting this property.", NULL }, ++ { "location", bppy_get_location, NULL, ++ "Location of the breakpoint, as specified by the user.", NULL}, ++ { "condition", bppy_get_condition, bppy_set_condition, ++ "Condition of the breakpoint, as specified by the user,\ ++or None if no condition set."}, ++ { "commands", bppy_get_commands, NULL, ++ "Commands of the breakpoint, as specified by the user."}, ++ { NULL } /* Sentinel. */ ++}; ++ ++static PyMethodDef breakpoint_object_methods[] = ++{ ++ { "is_valid", bppy_is_valid, METH_NOARGS, ++ "Return true if this breakpoint is valid, false if not." }, ++ { NULL } /* Sentinel. */ ++}; ++ ++static PyTypeObject breakpoint_object_type = ++{ ++ PyObject_HEAD_INIT (NULL) ++ 0, /*ob_size*/ ++ "gdb.Breakpoint", /*tp_name*/ ++ sizeof (breakpoint_object), /*tp_basicsize*/ ++ 0, /*tp_itemsize*/ ++ 0, /*tp_dealloc*/ ++ 0, /*tp_print*/ ++ 0, /*tp_getattr*/ ++ 0, /*tp_setattr*/ ++ 0, /*tp_compare*/ ++ 0, /*tp_repr*/ ++ 0, /*tp_as_number*/ ++ 0, /*tp_as_sequence*/ ++ 0, /*tp_as_mapping*/ ++ 0, /*tp_hash */ ++ 0, /*tp_call*/ ++ 0, /*tp_str*/ ++ 0, /*tp_getattro*/ ++ 0, /*tp_setattro*/ ++ 0, /*tp_as_buffer*/ ++ Py_TPFLAGS_DEFAULT, /*tp_flags*/ ++ "GDB breakpoint object", /* tp_doc */ ++ 0, /* tp_traverse */ ++ 0, /* tp_clear */ ++ 0, /* tp_richcompare */ ++ 0, /* tp_weaklistoffset */ ++ 0, /* tp_iter */ ++ 0, /* tp_iternext */ ++ breakpoint_object_methods, /* tp_methods */ ++ 0, /* tp_members */ ++ breakpoint_object_getset /* tp_getset */ ++}; +diff --git a/gdb/python/python-cmd.c b/gdb/python/python-cmd.c +index 36cde34..e6e3ac0 100644 +--- a/gdb/python/python-cmd.c ++++ b/gdb/python/python-cmd.c +@@ -47,8 +47,7 @@ static struct cmdpy_completer completers[] = + + #define N_COMPLETERS (sizeof (completers) / sizeof (completers[0])) + +-/* A gdb command. For the time being only ordinary commands (not +- set/show commands) are allowed. */ ++/* A gdb command. */ + struct cmdpy_object + { + PyObject_HEAD +@@ -68,7 +67,6 @@ typedef struct cmdpy_object cmdpy_object; + + static PyTypeObject cmdpy_object_type; + +- + /* Constants used by this module. */ + static PyObject *invoke_cst; + static PyObject *complete_cst; +@@ -265,10 +263,13 @@ cmdpy_completer (struct cmd_list_element *command, char *text, char *word) + *BASE_LIST is set to the final prefix command's list of + *sub-commands. + ++ START_LIST is the list in which the search starts. ++ + This function returns the xmalloc()d name of the new command. On + error sets the Python error and returns NULL. */ +-static char * +-parse_command_name (char *text, struct cmd_list_element ***base_list) ++char * ++gdbpy_parse_command_name (char *text, struct cmd_list_element ***base_list, ++ struct cmd_list_element **start_list) + { + struct cmd_list_element *elt; + int len = strlen (text); +@@ -301,7 +302,7 @@ parse_command_name (char *text, struct cmd_list_element ***base_list) + ; + if (i < 0) + { +- *base_list = &cmdlist; ++ *base_list = start_list; + return result; + } + +@@ -310,7 +311,7 @@ parse_command_name (char *text, struct cmd_list_element ***base_list) + prefix_text[i + 1] = '\0'; + + text = prefix_text; +- elt = lookup_cmd_1 (&text, cmdlist, NULL, 1); ++ elt = lookup_cmd_1 (&text, *start_list, NULL, 1); + if (!elt || elt == (struct cmd_list_element *) -1) + { + PyErr_Format (PyExc_RuntimeError, _("could not find command prefix %s"), +@@ -336,16 +337,16 @@ parse_command_name (char *text, struct cmd_list_element ***base_list) + + /* Object initializer; sets up gdb-side structures for command. + +- Use: __init__(NAME, CMDCLASS, [COMPLETERCLASS, [PREFIX]]). ++ Use: __init__(NAME, COMMAND_CLASS, [COMPLETER_CLASS, [PREFIX]]). + + NAME is the name of the command. It may consist of multiple words, + in which case the final word is the name of the new command, and + earlier words must be prefix commands. + +- CMDCLASS is the kind of command. It should be one of the COMMAND_* ++ COMMAND_CLASS is the kind of command. It should be one of the COMMAND_* + constants defined in the gdb module. + +- COMPLETERCLASS is the kind of completer. If not given, the ++ COMPLETER_CLASS is the kind of completer. If not given, the + "complete" method will be used. Otherwise, it should be one of the + COMPLETE_* constants defined in the gdb module. + +@@ -356,7 +357,7 @@ parse_command_name (char *text, struct cmd_list_element ***base_list) + + */ + static int +-cmdpy_init (PyObject *self, PyObject *args, PyObject *kwds) ++cmdpy_init (PyObject *self, PyObject *args, PyObject *kw) + { + cmdpy_object *obj = (cmdpy_object *) self; + char *name; +@@ -366,6 +367,8 @@ cmdpy_init (PyObject *self, PyObject *args, PyObject *kwds) + volatile struct gdb_exception except; + struct cmd_list_element **cmd_list; + char *cmd_name, *pfx_name; ++ static char *keywords[] = { "name", "command_class", "completer_class", ++ "prefix", NULL }; + PyObject *is_prefix = NULL; + int cmp; + +@@ -378,7 +381,7 @@ cmdpy_init (PyObject *self, PyObject *args, PyObject *kwds) + return -1; + } + +- if (! PyArg_ParseTuple (args, "si|iO", &name, &cmdtype, ++ if (! PyArg_ParseTupleAndKeywords (args, kw, "si|iO", keywords, &name, &cmdtype, + &completetype, &is_prefix)) + return -1; + +@@ -399,7 +402,7 @@ cmdpy_init (PyObject *self, PyObject *args, PyObject *kwds) + return -1; + } + +- cmd_name = parse_command_name (name, &cmd_list); ++ cmd_name = gdbpy_parse_command_name (name, &cmd_list, &cmdlist); + if (! cmd_name) + return -1; + +diff --git a/gdb/python/python-frame.c b/gdb/python/python-frame.c +new file mode 100644 +index 0000000..c257ac3 +--- /dev/null ++++ b/gdb/python/python-frame.c +@@ -0,0 +1,686 @@ ++/* Python interface to stack frames ++ ++ Copyright (C) 2008, 2009 Free Software Foundation, Inc. ++ ++ This file is part of GDB. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++#include "defs.h" ++#include "charset.h" ++#include "block.h" ++#include "frame.h" ++#include "exceptions.h" ++#include "symtab.h" ++#include "stack.h" ++#include "value.h" ++#include "python-internal.h" ++ ++typedef struct { ++ PyObject_HEAD ++ struct frame_id frame_id; ++ struct gdbarch *gdbarch; ++ ++ /* Marks that the FRAME_ID member actually holds the ID of the frame next ++ to this, and not this frames' ID itself. This is a hack to permit Python ++ frame objects which represent invalid frames (i.e., the last frame_info ++ in a corrupt stack). The problem arises from the fact that this code ++ relies on FRAME_ID to uniquely identify a frame, which is not always true ++ for the last "frame" in a corrupt stack (it can have a null ID, or the same ++ ID as the previous frame). Whenever get_prev_frame returns NULL, we ++ record the frame_id of the next frame and set FRAME_ID_IS_NEXT to 1. */ ++ int frame_id_is_next; ++} frame_object; ++ ++/* Require a valid frame. This must be called inside a TRY_CATCH, or ++ another context in which a gdb exception is allowed. */ ++#define FRAPY_REQUIRE_VALID(frame_obj, frame) \ ++ do { \ ++ frame = frame_object_to_frame_info (frame_obj); \ ++ if (frame == NULL) \ ++ error ("Frame is invalid."); \ ++ } while (0) ++ ++static PyTypeObject frame_object_type; ++ ++/* Returns the frame_info object corresponding to the given Python Frame ++ object. If the frame doesn't exist anymore (the frame id doesn't ++ correspond to any frame in the inferior), returns NULL. */ ++ ++static struct frame_info * ++frame_object_to_frame_info (frame_object *frame_obj) ++{ ++ struct frame_info *frame; ++ ++ frame = frame_find_by_id (frame_obj->frame_id); ++ if (frame == NULL) ++ return NULL; ++ ++ if (frame_obj->frame_id_is_next) ++ frame = get_prev_frame (frame); ++ ++ return frame; ++} ++ ++/* Called by the Python interpreter to obtain string representation ++ of the object. */ ++ ++static PyObject * ++frapy_str (PyObject *self) ++{ ++ char *s; ++ long len; ++ PyObject *result; ++ struct ui_file *strfile; ++ ++ strfile = mem_fileopen (); ++ fprint_frame_id (strfile, ((frame_object *) self)->frame_id); ++ s = ui_file_xstrdup (strfile, &len); ++ result = PyString_FromString (s); ++ xfree (s); ++ ++ return result; ++} ++ ++/* Implementation of gdb.Frame.is_valid (self) -> Boolean. ++ Returns True if the frame corresponding to the frame_id of this ++ object still exists in the inferior. */ ++ ++static PyObject * ++frapy_is_valid (PyObject *self, PyObject *args) ++{ ++ struct frame_info *frame; ++ ++ frame = frame_object_to_frame_info ((frame_object *) self); ++ if (frame == NULL) ++ Py_RETURN_FALSE; ++ ++ Py_RETURN_TRUE; ++} ++ ++/* Implementation of gdb.Frame.equals (self, other) -> Boolean. */ ++ ++static PyObject * ++frapy_equal_p (PyObject *self, PyObject *args) ++{ ++ int equalp = 0; /* Initialize to appease gcc warning. */ ++ frame_object *self_frame = (frame_object *) self; ++ frame_object *other; ++ volatile struct gdb_exception except; ++ ++ if (!PyArg_ParseTuple (args, "O!", &frame_object_type, &other)) ++ return NULL; ++ ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ equalp = frame_id_eq (self_frame->frame_id, other->frame_id); ++ } ++ GDB_PY_HANDLE_EXCEPTION (except); ++ ++ if (equalp) ++ Py_RETURN_TRUE; ++ ++ Py_RETURN_FALSE; ++} ++ ++/* Implementation of gdb.Frame.name (self) -> String. ++ Returns the name of the function corresponding to this frame. */ ++ ++static PyObject * ++frapy_name (PyObject *self, PyObject *args) ++{ ++ struct frame_info *frame; ++ char *name; ++ enum language lang; ++ PyObject *result; ++ volatile struct gdb_exception except; ++ ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ FRAPY_REQUIRE_VALID ((frame_object *) self, frame); ++ ++ find_frame_funname (frame, &name, &lang); ++ } ++ GDB_PY_HANDLE_EXCEPTION (except); ++ ++ if (name) ++ result = target_string_to_unicode (name, strlen (name)); ++ else ++ { ++ result = Py_None; ++ Py_INCREF (Py_None); ++ } ++ ++ return result; ++} ++ ++/* Implementation of gdb.Frame.type (self) -> Integer. ++ Returns the frame type, namely one of the gdb.*_FRAME constants. */ ++ ++static PyObject * ++frapy_type (PyObject *self, PyObject *args) ++{ ++ struct frame_info *frame; ++ enum frame_type type = NORMAL_FRAME;/* Initialize to appease gcc warning. */ ++ volatile struct gdb_exception except; ++ ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ FRAPY_REQUIRE_VALID ((frame_object *) self, frame); ++ ++ type = get_frame_type (frame); ++ } ++ GDB_PY_HANDLE_EXCEPTION (except); ++ ++ return PyInt_FromLong (type); ++} ++ ++/* Implementation of gdb.Frame.unwind_stop_reason (self) -> Integer. ++ Returns one of the gdb.FRAME_UNWIND_* constants. */ ++ ++static PyObject * ++frapy_unwind_stop_reason (PyObject *self, PyObject *args) ++{ ++ struct frame_info *frame = NULL; /* Initialize to appease gcc warning. */ ++ volatile struct gdb_exception except; ++ enum unwind_stop_reason stop_reason; ++ ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ FRAPY_REQUIRE_VALID ((frame_object *) self, frame); ++ } ++ GDB_PY_HANDLE_EXCEPTION (except); ++ ++ stop_reason = get_frame_unwind_stop_reason (frame); ++ ++ return PyInt_FromLong (stop_reason); ++} ++ ++/* Implementation of gdb.Frame.pc (self) -> Long. ++ Returns the frame's resume address. */ ++ ++static PyObject * ++frapy_pc (PyObject *self, PyObject *args) ++{ ++ CORE_ADDR pc = 0; /* Initialize to appease gcc warning. */ ++ struct frame_info *frame; ++ volatile struct gdb_exception except; ++ ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ FRAPY_REQUIRE_VALID ((frame_object *) self, frame); ++ ++ pc = get_frame_pc (frame); ++ } ++ GDB_PY_HANDLE_EXCEPTION (except); ++ ++ return PyLong_FromUnsignedLongLong (pc); ++} ++ ++/* Implementation of gdb.Frame.block (self) -> gdb.Block. ++ Returns the frame's code block. */ ++ ++static PyObject * ++frapy_block (PyObject *self, PyObject *args) ++{ ++ struct frame_info *frame; ++ struct block *block = NULL; ++ volatile struct gdb_exception except; ++ ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ FRAPY_REQUIRE_VALID ((frame_object *) self, frame); ++ ++ block = block_for_pc (get_frame_address_in_block (frame)); ++ } ++ GDB_PY_HANDLE_EXCEPTION (except); ++ ++ if (block) ++ return block_to_block_object (block); ++ ++ Py_RETURN_NONE; ++} ++ ++ ++/* Implementation of gdb.Frame.addr_in_block (self) -> Long. ++ Returns an address which falls within the frame's code block. */ ++ ++static PyObject * ++frapy_addr_in_block (PyObject *self, PyObject *args) ++{ ++ CORE_ADDR pc = 0; /* Initialize to appease gcc warning. */ ++ struct frame_info *frame; ++ volatile struct gdb_exception except; ++ ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ FRAPY_REQUIRE_VALID ((frame_object *) self, frame); ++ ++ pc = get_frame_address_in_block (frame); ++ } ++ GDB_PY_HANDLE_EXCEPTION (except); ++ ++ return PyLong_FromUnsignedLongLong (pc); ++} ++ ++/* Convert a frame_info struct to a Python Frame object. ++ Sets a Python exception and returns NULL on error. */ ++ ++static frame_object * ++frame_info_to_frame_object (struct frame_info *frame) ++{ ++ frame_object *frame_obj; ++ ++ frame_obj = PyObject_New (frame_object, &frame_object_type); ++ if (frame_obj == NULL) ++ { ++ PyErr_SetString (PyExc_MemoryError, "Could not allocate frame object."); ++ return NULL; ++ } ++ ++ /* Try to get the previous frame, to determine if this is the last frame ++ in a corrupt stack. If so, we need to store the frame_id of the next ++ frame and not of this one (which is possibly invalid). */ ++ if (get_prev_frame (frame) == NULL ++ && get_frame_unwind_stop_reason (frame) != UNWIND_NO_REASON ++ && get_next_frame (frame) != NULL) ++ { ++ frame_obj->frame_id = get_frame_id (get_next_frame (frame)); ++ frame_obj->frame_id_is_next = 1; ++ } ++ else ++ { ++ frame_obj->frame_id = get_frame_id (frame); ++ frame_obj->frame_id_is_next = 0; ++ } ++ ++ frame_obj->gdbarch = get_frame_arch (frame); ++ ++ return frame_obj; ++} ++ ++/* Implementation of gdb.Frame.older (self) -> gdb.Frame. ++ Returns the frame immediately older (outer) to this frame, or None if ++ there isn't one. */ ++ ++static PyObject * ++frapy_older (PyObject *self, PyObject *args) ++{ ++ struct frame_info *frame, *prev; ++ volatile struct gdb_exception except; ++ PyObject *prev_obj = NULL; /* Initialize to appease gcc warning. */ ++ ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ FRAPY_REQUIRE_VALID ((frame_object *) self, frame); ++ ++ prev = get_prev_frame (frame); ++ if (prev) ++ prev_obj = (PyObject *) frame_info_to_frame_object (prev); ++ else ++ { ++ Py_INCREF (Py_None); ++ prev_obj = Py_None; ++ } ++ } ++ GDB_PY_HANDLE_EXCEPTION (except); ++ ++ return prev_obj; ++} ++ ++/* Implementation of gdb.Frame.newer (self) -> gdb.Frame. ++ Returns the frame immediately newer (inner) to this frame, or None if ++ there isn't one. */ ++ ++static PyObject * ++frapy_newer (PyObject *self, PyObject *args) ++{ ++ struct frame_info *frame, *next; ++ volatile struct gdb_exception except; ++ PyObject *next_obj = NULL; /* Initialize to appease gcc warning. */ ++ ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ FRAPY_REQUIRE_VALID ((frame_object *) self, frame); ++ ++ next = get_next_frame (frame); ++ if (next) ++ next_obj = (PyObject *) frame_info_to_frame_object (next); ++ else ++ { ++ Py_INCREF (Py_None); ++ next_obj = Py_None; ++ } ++ } ++ GDB_PY_HANDLE_EXCEPTION (except); ++ ++ return next_obj; ++} ++ ++/* Implementation of gdb.Frame.find_sal (self) -> gdb.Symtab_and_line. ++ Returns the frame's symtab and line. */ ++ ++static PyObject * ++frapy_find_sal (PyObject *self, PyObject *args) ++{ ++ struct frame_info *frame; ++ struct symtab_and_line sal; ++ volatile struct gdb_exception except; ++ PyObject *sal_obj = NULL; /* Initialize to appease gcc warning. */ ++ ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ FRAPY_REQUIRE_VALID ((frame_object *) self, frame); ++ ++ find_frame_sal (frame, &sal); ++ sal_obj = symtab_and_line_to_sal_object (sal); ++ } ++ GDB_PY_HANDLE_EXCEPTION (except); ++ ++ return sal_obj; ++} ++ ++/* Implementation of gdb.Frame.read_var (self, variable) -> gdb.Value. ++ Returns the value of the given variable in this frame. The argument can be ++ either a gdb.Symbol or a string. Returns None if GDB can't find the ++ specified variable. */ ++ ++static PyObject * ++frapy_read_var (PyObject *self, PyObject *args) ++{ ++ struct frame_info *frame; ++ PyObject *sym_obj; ++ struct symbol *var = NULL; /* gcc-4.3.2 false warning. */ ++ struct value *val = NULL; ++ volatile struct gdb_exception except; ++ ++ if (!PyArg_ParseTuple (args, "O", &sym_obj)) ++ return NULL; ++ ++ if (PyObject_TypeCheck (sym_obj, &symbol_object_type)) ++ var = symbol_object_to_symbol (sym_obj); ++ else if (gdbpy_is_string (sym_obj)) ++ { ++ char *var_name; ++ struct block *block = NULL; ++ struct cleanup *cleanup; ++ volatile struct gdb_exception except; ++ ++ var_name = python_string_to_target_string (sym_obj); ++ if (!var_name) ++ return NULL; ++ cleanup = make_cleanup (xfree, var_name); ++ ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ FRAPY_REQUIRE_VALID ((frame_object *) self, frame); ++ ++ block = block_for_pc (get_frame_address_in_block (frame)); ++ var = lookup_symbol (var_name, block, VAR_DOMAIN, NULL); ++ } ++ GDB_PY_HANDLE_EXCEPTION (except); ++ ++ if (!var) ++ { ++ PyErr_Format (PyExc_ValueError, ++ _("variable '%s' not found"), var_name); ++ do_cleanups (cleanup); ++ ++ return NULL; ++ } ++ ++ do_cleanups (cleanup); ++ } ++ else ++ { ++ PyErr_SetString (PyExc_TypeError, ++ _("argument must be a symbol or string")); ++ return NULL; ++ } ++ ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ FRAPY_REQUIRE_VALID ((frame_object *) self, frame); ++ ++ val = read_var_value (var, frame); ++ } ++ GDB_PY_HANDLE_EXCEPTION (except); ++ ++ if (val) ++ return value_to_value_object (val); ++ ++ Py_RETURN_NONE; ++} ++ ++/* Implementation of gdb.frames () -> (gdb.Frame, ...). ++ Returns a tuple of all frame objects. */ ++ ++PyObject * ++gdbpy_frames (PyObject *self, PyObject *args) ++{ ++ int result = 0; ++ struct frame_info *frame; ++ frame_object *frame_obj; ++ PyObject *list, *tuple; ++ volatile struct gdb_exception except; ++ ++ list = PyList_New (0); ++ if (list == NULL) ++ { ++ PyErr_SetString (PyExc_MemoryError, "Could not allocate frames list."); ++ return NULL; ++ } ++ ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ for (frame = get_current_frame (); frame; frame = get_prev_frame (frame)) ++ { ++ frame_obj = frame_info_to_frame_object (frame); ++ if (frame_obj == NULL) ++ { ++ Py_DECREF (list); ++ list = NULL; ++ break; ++ } ++ ++ PyList_Append (list, (PyObject *) frame_obj); ++ } ++ } ++ if (except.reason < 0) ++ { ++ Py_DECREF (list); ++ return PyErr_Format (except.reason == RETURN_QUIT ++ ? PyExc_KeyboardInterrupt : PyExc_RuntimeError, ++ "%s", except.message); ++ } ++ ++ if (list) ++ { ++ tuple = PyList_AsTuple (list); ++ Py_DECREF (list); ++ } ++ else ++ tuple = NULL; ++ ++ return tuple; ++} ++ ++/* Implementation of gdb.newest_frame () -> gdb.Frame. ++ Returns the newest frame object. */ ++ ++PyObject * ++gdbpy_newest_frame (PyObject *self, PyObject *args) ++{ ++ struct frame_info *frame; ++ frame_object *frame_obj = NULL; /* Initialize to appease gcc warning. */ ++ volatile struct gdb_exception except; ++ ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ frame = get_current_frame (); ++ frame_obj = frame_info_to_frame_object (frame); ++ } ++ GDB_PY_HANDLE_EXCEPTION (except); ++ ++ return (PyObject *) frame_obj; ++} ++ ++/* Implementation of gdb.selected_frame () -> gdb.Frame. ++ Returns the selected frame object. */ ++ ++PyObject * ++gdbpy_selected_frame (PyObject *self, PyObject *args) ++{ ++ struct frame_info *frame; ++ frame_object *frame_obj = NULL; /* Initialize to appease gcc warning. */ ++ volatile struct gdb_exception except; ++ ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ frame = get_selected_frame ("No frame is currently selected."); ++ frame_obj = frame_info_to_frame_object (frame); ++ } ++ GDB_PY_HANDLE_EXCEPTION (except); ++ ++ return (PyObject *) frame_obj; ++} ++ ++/* Implementation of gdb.stop_reason_string (Integer) -> String. ++ Return a string explaining the unwind stop reason. */ ++ ++PyObject * ++gdbpy_frame_stop_reason_string (PyObject *self, PyObject *args) ++{ ++ int reason; ++ const char *str; ++ ++ if (!PyArg_ParseTuple (args, "i", &reason)) ++ return NULL; ++ ++ if (reason < 0 || reason > UNWIND_NO_SAVED_PC) ++ { ++ PyErr_SetString (PyExc_ValueError, "Invalid frame stop reason."); ++ return NULL; ++ } ++ ++ str = frame_stop_reason_string (reason); ++ return PyUnicode_Decode (str, strlen (str), host_charset (), NULL); ++} ++ ++/* Sets up the Frame API in the gdb module. */ ++ ++void ++gdbpy_initialize_frames (void) ++{ ++ frame_object_type.tp_new = PyType_GenericNew; ++ if (PyType_Ready (&frame_object_type) < 0) ++ return; ++ ++ /* Note: These would probably be best exposed as class attributes of Frame, ++ but I don't know how to do it except by messing with the type's dictionary. ++ That seems too messy. */ ++ PyModule_AddIntConstant (gdb_module, "NORMAL_FRAME", NORMAL_FRAME); ++ PyModule_AddIntConstant (gdb_module, "DUMMY_FRAME", DUMMY_FRAME); ++ PyModule_AddIntConstant (gdb_module, "SIGTRAMP_FRAME", SIGTRAMP_FRAME); ++ PyModule_AddIntConstant (gdb_module, "SENTINEL_FRAME", SENTINEL_FRAME); ++ PyModule_AddIntConstant (gdb_module, ++ "FRAME_UNWIND_NO_REASON", UNWIND_NO_REASON); ++ PyModule_AddIntConstant (gdb_module, ++ "FRAME_UNWIND_NULL_ID", UNWIND_NULL_ID); ++ PyModule_AddIntConstant (gdb_module, ++ "FRAME_UNWIND_FIRST_ERROR", UNWIND_FIRST_ERROR); ++ PyModule_AddIntConstant (gdb_module, ++ "FRAME_UNWIND_INNER_ID", UNWIND_INNER_ID); ++ PyModule_AddIntConstant (gdb_module, ++ "FRAME_UNWIND_SAME_ID", UNWIND_SAME_ID); ++ PyModule_AddIntConstant (gdb_module, ++ "FRAME_UNWIND_NO_SAVED_PC", UNWIND_NO_SAVED_PC); ++ ++ Py_INCREF (&frame_object_type); ++ PyModule_AddObject (gdb_module, "Frame", (PyObject *) &frame_object_type); ++} ++ ++ ++ ++static PyMethodDef frame_object_methods[] = { ++ { "equals", frapy_equal_p, METH_VARARGS, ++ "equals (frame) -> Boolean.\n\ ++Compare this frame to the given frame." }, ++ { "is_valid", frapy_is_valid, METH_NOARGS, ++ "is_valid () -> Boolean.\n\ ++Return true if this frame is valid, false if not." }, ++ { "name", frapy_name, METH_NOARGS, ++ "name () -> String.\n\ ++Return the function name of the frame, or None if it can't be determined." }, ++ { "type", frapy_type, METH_NOARGS, ++ "type () -> Integer.\n\ ++Return the type of the frame." }, ++ { "unwind_stop_reason", frapy_unwind_stop_reason, METH_NOARGS, ++ "unwind_stop_reason () -> Integer.\n\ ++Return the reason why it's not possible to find frames older than this." }, ++ { "pc", frapy_pc, METH_NOARGS, ++ "pc () -> Long.\n\ ++Return the frame's resume address." }, ++ { "block", frapy_block, METH_NOARGS, ++ "block () -> gdb.Block.\n\ ++Return the frame's code block." }, ++ { "addr_in_block", frapy_addr_in_block, METH_NOARGS, ++ "addr_in_block () -> Long.\n\ ++Return an address which falls within the frame's code block." }, ++ { "older", frapy_older, METH_NOARGS, ++ "older () -> gdb.Frame.\n\ ++Return the frame immediately older (outer) to this frame." }, ++ { "newer", frapy_newer, METH_NOARGS, ++ "newer () -> gdb.Frame.\n\ ++Return the frame immetidaely newer (inner) to this frame." }, ++ { "find_sal", frapy_find_sal, METH_NOARGS, ++ "find_sal () -> gdb.Symtab_and_line.\n\ ++Return the frame's symtab and line." }, ++ { "read_var", frapy_read_var, METH_VARARGS, ++ "read_var (variable) -> gdb.Value.\n\ ++Return the value of the variable in this frame." }, ++ {NULL} /* Sentinel */ ++}; ++ ++static PyTypeObject frame_object_type = { ++ PyObject_HEAD_INIT (NULL) ++ 0, /* ob_size */ ++ "gdb.Frame", /* tp_name */ ++ sizeof (frame_object), /* tp_basicsize */ ++ 0, /* tp_itemsize */ ++ 0, /* tp_dealloc */ ++ 0, /* tp_print */ ++ 0, /* tp_getattr */ ++ 0, /* tp_setattr */ ++ 0, /* tp_compare */ ++ 0, /* tp_repr */ ++ 0, /* tp_as_number */ ++ 0, /* tp_as_sequence */ ++ 0, /* tp_as_mapping */ ++ 0, /* tp_hash */ ++ 0, /* tp_call */ ++ frapy_str, /* tp_str */ ++ 0, /* tp_getattro */ ++ 0, /* tp_setattro */ ++ 0, /* tp_as_buffer */ ++ Py_TPFLAGS_DEFAULT, /* tp_flags */ ++ "GDB frame object", /* tp_doc */ ++ 0, /* tp_traverse */ ++ 0, /* tp_clear */ ++ 0, /* tp_richcompare */ ++ 0, /* tp_weaklistoffset */ ++ 0, /* tp_iter */ ++ 0, /* tp_iternext */ ++ frame_object_methods /* tp_methods */ ++}; +diff --git a/gdb/python/python-function.c b/gdb/python/python-function.c +new file mode 100644 +index 0000000..4a85a33 +--- /dev/null ++++ b/gdb/python/python-function.c +@@ -0,0 +1,180 @@ ++/* Convenience functions implemented in Python. ++ ++ Copyright (C) 2008, 2009 Free Software Foundation, Inc. ++ ++ This file is part of GDB. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++ ++#include "defs.h" ++#include "value.h" ++#include "exceptions.h" ++#include "python-internal.h" ++#include "charset.h" ++#include "gdbcmd.h" ++#include "cli/cli-decode.h" ++#include "completer.h" ++#include "expression.h" ++ ++static PyTypeObject fnpy_object_type; ++ ++ ++ ++static PyObject * ++convert_values_to_python (int argc, struct value **argv) ++{ ++ int i; ++ PyObject *result = PyTuple_New (argc); ++ for (i = 0; i < argc; ++i) ++ { ++ PyObject *elt = value_to_value_object (argv[i]); ++ if (! elt) ++ { ++ Py_DECREF (result); ++ error (_("Could not convert value to Python object.")); ++ } ++ PyTuple_SetItem (result, i, elt); ++ } ++ return result; ++} ++ ++/* Call a Python function object's invoke method. */ ++ ++static struct value * ++fnpy_call (void *cookie, int argc, struct value **argv) ++{ ++ int i; ++ struct value *value = NULL; ++ PyObject *result, *callable, *args; ++ struct cleanup *cleanup; ++ PyGILState_STATE state; ++ ++ state = PyGILState_Ensure (); ++ cleanup = make_cleanup_py_restore_gil (&state); ++ ++ args = convert_values_to_python (argc, argv); ++ ++ callable = PyObject_GetAttrString ((PyObject *) cookie, "invoke"); ++ if (! callable) ++ { ++ Py_DECREF (args); ++ error (_("No method named 'invoke' in object.")); ++ } ++ ++ result = PyObject_Call (callable, args, NULL); ++ Py_DECREF (callable); ++ Py_DECREF (args); ++ ++ if (!result) ++ { ++ gdbpy_print_stack (); ++ error (_("Error while executing Python code.")); ++ } ++ ++ value = convert_value_from_python (result); ++ if (value == NULL) ++ { ++ Py_DECREF (result); ++ gdbpy_print_stack (); ++ error (_("Error while executing Python code.")); ++ } ++ ++ Py_DECREF (result); ++ do_cleanups (cleanup); ++ ++ return value; ++} ++ ++/* Initializer for a Function object. It takes one argument, the name ++ of the function. */ ++ ++static int ++fnpy_init (PyObject *self, PyObject *args, PyObject *kwds) ++{ ++ char *name, *docstring = NULL; ++ if (! PyArg_ParseTuple (args, "s", &name)) ++ return -1; ++ Py_INCREF (self); ++ ++ if (PyObject_HasAttrString (self, "__doc__")) ++ { ++ PyObject *ds_obj = PyObject_GetAttrString (self, "__doc__"); ++ if (ds_obj && gdbpy_is_string (ds_obj)) ++ /* Nothing ever frees this. */ ++ docstring = python_string_to_host_string (ds_obj); ++ } ++ if (! docstring) ++ docstring = _("This function is not documented."); ++ ++ add_internal_function (name, docstring, fnpy_call, self); ++ return 0; ++} ++ ++/* Initialize internal function support. */ ++ ++void ++gdbpy_initialize_functions (void) ++{ ++ if (PyType_Ready (&fnpy_object_type) < 0) ++ return; ++ ++ Py_INCREF (&fnpy_object_type); ++ PyModule_AddObject (gdb_module, "Function", (PyObject *) &fnpy_object_type); ++} ++ ++ ++ ++static PyTypeObject fnpy_object_type = ++{ ++ PyObject_HEAD_INIT (NULL) ++ 0, /*ob_size*/ ++ "gdb.Function", /*tp_name*/ ++ sizeof (PyObject), /*tp_basicsize*/ ++ 0, /*tp_itemsize*/ ++ 0, /*tp_dealloc*/ ++ 0, /*tp_print*/ ++ 0, /*tp_getattr*/ ++ 0, /*tp_setattr*/ ++ 0, /*tp_compare*/ ++ 0, /*tp_repr*/ ++ 0, /*tp_as_number*/ ++ 0, /*tp_as_sequence*/ ++ 0, /*tp_as_mapping*/ ++ 0, /*tp_hash */ ++ 0, /*tp_call*/ ++ 0, /*tp_str*/ ++ 0, /*tp_getattro*/ ++ 0, /*tp_setattro*/ ++ 0, /*tp_as_buffer*/ ++ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ ++ "GDB function object", /* tp_doc */ ++ 0, /* tp_traverse */ ++ 0, /* tp_clear */ ++ 0, /* tp_richcompare */ ++ 0, /* tp_weaklistoffset */ ++ 0, /* tp_iter */ ++ 0, /* tp_iternext */ ++ 0, /* tp_methods */ ++ 0, /* tp_members */ ++ 0, /* tp_getset */ ++ 0, /* tp_base */ ++ 0, /* tp_dict */ ++ 0, /* tp_descr_get */ ++ 0, /* tp_descr_set */ ++ 0, /* tp_dictoffset */ ++ fnpy_init, /* tp_init */ ++ 0, /* tp_alloc */ ++ PyType_GenericNew /* tp_new */ ++}; +diff --git a/gdb/python/python-hooks.c b/gdb/python/python-hooks.c +new file mode 100644 +index 0000000..a3140bc +--- /dev/null ++++ b/gdb/python/python-hooks.c +@@ -0,0 +1,50 @@ ++/* Notifications from gdb to Python ++ ++ Copyright (C) 2008 Free Software Foundation, Inc. ++ ++ This file is part of GDB. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++#include "defs.h" ++#include "cli/cli-decode.h" ++#include "charset.h" ++#include "python.h" ++#include "python-internal.h" ++#include "observer.h" ++ ++PyObject * ++gdbpy_get_hook_function (const char *name) ++{ ++ PyObject *hooks; ++ PyObject *result; ++ ++ if (! PyObject_HasAttrString (gdb_module, "hooks")) ++ return NULL; ++ hooks = PyObject_GetAttrString (gdb_module, "hooks"); ++ if (! hooks) ++ return NULL; ++ /* The cast is because the Python function doesn't declare const argument. ++ This is a problem in Python version 2.4, but not in 2.5. */ ++ if (! PyObject_HasAttrString (hooks, (char *) name)) ++ { ++ Py_DECREF (hooks); ++ return NULL; ++ } ++ /* The cast is because the Python function doesn't declare const argument. ++ This is a problem in Python version 2.4, but not in 2.5. */ ++ result = PyObject_GetAttrString (hooks, (char *) name); ++ Py_DECREF (hooks); ++ return result; ++} +diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h +index 02dbfc4..4aae0aa 100644 +--- a/gdb/python/python-internal.h ++++ b/gdb/python/python-internal.h +@@ -33,6 +33,7 @@ + + #if HAVE_LIBPYTHON2_4 + #include "python2.4/Python.h" ++#include "python2.4/frameobject.h" + /* Py_ssize_t is not defined until 2.5. + Logical type for Py_ssize_t is Py_intptr_t, but that fails in 64-bit + compilation due to several apparent mistakes in python2.4 API, so we +@@ -40,8 +41,10 @@ + typedef int Py_ssize_t; + #elif HAVE_LIBPYTHON2_5 + #include "python2.5/Python.h" ++#include "python2.5/frameobject.h" + #elif HAVE_LIBPYTHON2_6 + #include "python2.6/Python.h" ++#include "python2.6/frameobject.h" + #else + #error "Unable to find usable Python.h" + #endif +@@ -58,23 +61,69 @@ typedef int Py_ssize_t; + #define PyEval_ReleaseLock() 0 + #endif + ++#include "command.h" ++ ++struct block; ++struct symbol; ++struct symtab_and_line; + struct value; + + extern PyObject *gdb_module; ++extern PyTypeObject block_object_type; + extern PyTypeObject value_object_type; ++extern PyTypeObject symbol_object_type; + + PyObject *gdbpy_history (PyObject *self, PyObject *args); +- ++PyObject *gdbpy_breakpoints (PyObject *, PyObject *); ++PyObject *gdbpy_frames (PyObject *, PyObject *); ++PyObject *gdbpy_newest_frame (PyObject *, PyObject *); ++PyObject *gdbpy_frame_stop_reason_string (PyObject *, PyObject *); ++PyObject *gdbpy_lookup_symbol (PyObject *self, PyObject *args, PyObject *kw); ++PyObject *gdbpy_selected_frame (PyObject *self, PyObject *args); ++PyObject *gdbpy_block_for_pc (PyObject *self, PyObject *args); ++PyObject *gdbpy_read_memory (PyObject *self, PyObject *args); ++PyObject *gdbpy_write_memory (PyObject *self, PyObject *args); ++ ++PyObject *symtab_and_line_to_sal_object (struct symtab_and_line sal); ++PyObject *symtab_to_symtab_object (struct symtab *symtab); ++PyObject *symbol_to_symbol_object (struct symbol *sym); ++PyObject *block_to_block_object (struct block *block); + PyObject *value_to_value_object (struct value *v); ++PyObject *type_to_type_object (struct type *); ++PyObject *objfile_to_objfile_object (struct objfile *); + ++PyObject *objfpy_get_printers (PyObject *, void *); ++ ++struct block *block_object_to_block (PyObject *obj); ++struct symbol *symbol_object_to_symbol (PyObject *obj); ++struct value *value_object_to_value (PyObject *self); + struct value *convert_value_from_python (PyObject *obj); ++struct type *type_object_to_type (PyObject *obj); ++ ++PyObject *gdbpy_get_hook_function (const char *); + + void gdbpy_initialize_values (void); ++void gdbpy_initialize_breakpoints (void); ++void gdbpy_initialize_frames (void); ++void gdbpy_initialize_symtabs (void); + void gdbpy_initialize_commands (void); ++void gdbpy_initialize_symbols (void); ++void gdbpy_initialize_types (void); ++void gdbpy_initialize_blocks (void); ++void gdbpy_initialize_functions (void); ++void gdbpy_initialize_objfile (void); ++void gdbpy_initialize_parameters (void); ++void gdbpy_initialize_membuf (void); + + struct cleanup *make_cleanup_py_decref (PyObject *py); + struct cleanup *make_cleanup_py_restore_gil (PyGILState_STATE *state); + ++char *gdbpy_parse_command_name (char *text, ++ struct cmd_list_element ***base_list, ++ struct cmd_list_element **start_list); ++ ++PyObject *gdbpy_parameter_value (enum var_types, void *); ++ + /* Use this after a TRY_EXCEPT to throw the appropriate Python + exception. */ + #define GDB_PY_HANDLE_EXCEPTION(Exception) \ +@@ -85,6 +134,19 @@ struct cleanup *make_cleanup_py_restore_gil (PyGILState_STATE *state); + "%s", Exception.message); \ + } while (0) + ++/* Use this after a TRY_EXCEPT to throw the appropriate Python ++ exception. This macro is for use inside setter functions. */ ++#define GDB_PY_SET_HANDLE_EXCEPTION(Exception) \ ++ do { \ ++ if (Exception.reason < 0) \ ++ { \ ++ PyErr_Format (Exception.reason == RETURN_QUIT \ ++ ? PyExc_KeyboardInterrupt : PyExc_RuntimeError, \ ++ "%s", Exception.message); \ ++ return -1; \ ++ } \ ++ } while (0) ++ + + void gdbpy_print_stack (void); + +@@ -95,6 +157,21 @@ char *python_string_to_host_string (PyObject *obj); + PyObject *target_string_to_unicode (const gdb_byte *str, int length); + int gdbpy_is_string (PyObject *obj); + ++int gdbpy_is_value_object (PyObject *obj); ++ ++/* Note that these are declared here, and not in python.h with the ++ other pretty-printer functions, because they refer to PyObject. */ ++char *apply_varobj_pretty_printer (PyObject *print_obj, ++ struct value **replacement); ++PyObject *gdbpy_get_varobj_pretty_printer (struct value *value); ++PyObject *gdbpy_instantiate_printer (PyObject *cons, PyObject *value); ++char *gdbpy_get_display_hint (PyObject *printer); ++ ++extern PyObject *gdbpy_children_cst; ++extern PyObject *gdbpy_to_string_cst; ++extern PyObject *gdbpy_display_hint_cst; + extern PyObject *gdbpy_doc_cst; + ++int get_addr_from_python (PyObject *obj, CORE_ADDR *addr); ++ + #endif /* GDB_PYTHON_INTERNAL_H */ +diff --git a/gdb/python/python-membuf.c b/gdb/python/python-membuf.c +new file mode 100644 +index 0000000..a4c7d74 +--- /dev/null ++++ b/gdb/python/python-membuf.c +@@ -0,0 +1,243 @@ ++/* Python interface to the inferior memory. ++ ++ Copyright (C) 2008, 2009 Free Software Foundation, Inc. ++ ++ This file is part of GDB. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++#include "defs.h" ++#include "exceptions.h" ++#include "gdbcore.h" ++#include "python-internal.h" ++ ++typedef struct { ++ PyObject_HEAD ++ void *buffer; ++ ++ /* These are kept just for mbpy_str. */ ++ CORE_ADDR addr; ++ CORE_ADDR length; ++} membuf_object; ++ ++static PyTypeObject membuf_object_type; ++ ++/* Implementation of gdb.read_memory (address, length). ++ Returns a Python buffer object with LENGTH bytes of the inferior's memory ++ at ADDRESS. Both arguments are integers. */ ++ ++PyObject * ++gdbpy_read_memory (PyObject *self, PyObject *args) ++{ ++ CORE_ADDR addr, length; ++ void *buffer; ++ membuf_object *membuf_obj; ++ struct cleanup *cleanups; ++ volatile struct gdb_exception except; ++ ++ /* Assume CORE_ADDR corresponds to unsigned long. */ ++ if (! PyArg_ParseTuple (args, "kk", &addr, &length)) ++ return NULL; ++ ++ buffer = xmalloc (length); ++ cleanups = make_cleanup (xfree, buffer); ++ ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ read_memory (addr, buffer, length); ++ } ++ GDB_PY_HANDLE_EXCEPTION (except); ++ ++ discard_cleanups (cleanups); ++ ++ membuf_obj = PyObject_New (membuf_object, &membuf_object_type); ++ if (membuf_obj == NULL) ++ { ++ xfree (buffer); ++ PyErr_SetString (PyExc_MemoryError, ++ "Could not allocate memory buffer object."); ++ return NULL; ++ } ++ ++ membuf_obj->buffer = buffer; ++ ++ membuf_obj->addr = addr; ++ membuf_obj->length = length; ++ ++ return PyBuffer_FromReadWriteObject ((PyObject *) membuf_obj, 0, Py_END_OF_BUFFER); ++} ++ ++/* Implementation of gdb.write_memory (address, buffer [, length]). ++ Writes the contents of BUFFER (a Python object supporting the read buffer ++ protocol) at ADDRESS in the inferior's memory. Write LENGTH bytes from ++ BUFFER, or its entire contents if the argument is not provided. The ++ function returns nothing. */ ++ ++PyObject * ++gdbpy_write_memory (PyObject *self, PyObject *args) ++{ ++ int buf_len; ++ const char *buffer; ++ long length = -1; ++ CORE_ADDR addr; ++ volatile struct gdb_exception except; ++ ++ /* Assume CORE_ADDR corresponds to unsigned long. */ ++ if (! PyArg_ParseTuple (args, "ks#|l", &addr, &buffer, &buf_len, &length)) ++ return NULL; ++ ++ if (length == -1) ++ length = buf_len; ++ ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ write_memory (addr, buffer, length); ++ } ++ GDB_PY_HANDLE_EXCEPTION (except); ++ ++ Py_RETURN_NONE; ++} ++ ++/* Destructor of Membuf objects. */ ++ ++static void ++mbpy_dealloc (PyObject *self) ++{ ++ xfree (((membuf_object *) self)->buffer); ++ self->ob_type->tp_free (self); ++} ++ ++/* Return a description of the Membuf object. */ ++ ++static PyObject * ++mbpy_str (PyObject *self) ++{ ++ membuf_object *membuf_obj = (membuf_object *) self; ++ ++ return PyString_FromFormat ("memory buffer for address %s, %s bytes long", ++ paddress (membuf_obj->addr), ++ pulongest (membuf_obj->length)); ++} ++ ++static Py_ssize_t ++get_read_buffer (PyObject *self, Py_ssize_t segment, void **ptrptr) ++{ ++ membuf_object *membuf_obj = (membuf_object *) self; ++ ++ if (segment) ++ { ++ PyErr_SetString (PyExc_SystemError, ++ "The memory buffer supports only one segment."); ++ return -1; ++ } ++ ++ *ptrptr = membuf_obj->buffer; ++ ++ return membuf_obj->length; ++} ++ ++static Py_ssize_t ++get_write_buffer (PyObject *self, Py_ssize_t segment, void **ptrptr) ++{ ++ return get_read_buffer (self, segment, ptrptr); ++} ++ ++static Py_ssize_t ++get_seg_count (PyObject *self, Py_ssize_t *lenp) ++{ ++ if (lenp) ++ *lenp = ((membuf_object *) self)->length; ++ ++ return 1; ++} ++ ++static Py_ssize_t ++get_char_buffer (PyObject *self, Py_ssize_t segment, char **ptrptr) ++{ ++ void *ptr = NULL; ++ Py_ssize_t ret; ++ ++ ret = get_read_buffer (self, segment, &ptr); ++ *ptrptr = (char *) ptr; ++ ++ return ret; ++} ++ ++/* Python doesn't provide a decent way to get compatibility here. */ ++#if HAVE_LIBPYTHON2_4 ++#define CHARBUFFERPROC_NAME getcharbufferproc ++#else ++#define CHARBUFFERPROC_NAME charbufferproc ++#endif ++ ++static PyBufferProcs buffer_procs = { ++ get_read_buffer, ++ get_write_buffer, ++ get_seg_count, ++ /* The cast here works around a difference between Python 2.4 and ++ Python 2.5. */ ++ (CHARBUFFERPROC_NAME) get_char_buffer ++}; ++ ++static PyTypeObject membuf_object_type = { ++ PyObject_HEAD_INIT (NULL) ++ 0, /*ob_size*/ ++ "gdb.Membuf", /*tp_name*/ ++ sizeof (membuf_object), /*tp_basicsize*/ ++ 0, /*tp_itemsize*/ ++ mbpy_dealloc, /*tp_dealloc*/ ++ 0, /*tp_print*/ ++ 0, /*tp_getattr*/ ++ 0, /*tp_setattr*/ ++ 0, /*tp_compare*/ ++ 0, /*tp_repr*/ ++ 0, /*tp_as_number*/ ++ 0, /*tp_as_sequence*/ ++ 0, /*tp_as_mapping*/ ++ 0, /*tp_hash */ ++ 0, /*tp_call*/ ++ mbpy_str, /*tp_str*/ ++ 0, /*tp_getattro*/ ++ 0, /*tp_setattro*/ ++ &buffer_procs, /*tp_as_buffer*/ ++ Py_TPFLAGS_DEFAULT, /*tp_flags*/ ++ "GDB memory buffer object", /*tp_doc*/ ++ 0, /* tp_traverse */ ++ 0, /* tp_clear */ ++ 0, /* tp_richcompare */ ++ 0, /* tp_weaklistoffset */ ++ 0, /* tp_iter */ ++ 0, /* tp_iternext */ ++ 0, /* tp_methods */ ++ 0, /* tp_members */ ++ 0, /* tp_getset */ ++ 0, /* tp_base */ ++ 0, /* tp_dict */ ++ 0, /* tp_descr_get */ ++ 0, /* tp_descr_set */ ++ 0, /* tp_dictoffset */ ++ 0, /* tp_init */ ++ 0, /* tp_alloc */ ++ PyType_GenericNew /* tp_new */ ++}; ++ ++void ++gdbpy_initialize_membuf (void) ++{ ++ if (PyType_Ready (&membuf_object_type) < 0) ++ return; ++ ++ Py_INCREF (&membuf_object_type); ++ PyModule_AddObject (gdb_module, "Membuf", (PyObject *) &membuf_object_type); ++} +diff --git a/gdb/python/python-objfile.c b/gdb/python/python-objfile.c +new file mode 100644 +index 0000000..e97d3a2 +--- /dev/null ++++ b/gdb/python/python-objfile.c +@@ -0,0 +1,221 @@ ++/* Python interface to objfiles. ++ ++ Copyright (C) 2008, 2009 Free Software Foundation, Inc. ++ ++ This file is part of GDB. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++#include "defs.h" ++#include "python-internal.h" ++#include "charset.h" ++#include "objfiles.h" ++ ++typedef struct ++{ ++ PyObject_HEAD ++ ++ /* The corresponding objfile. */ ++ struct objfile *objfile; ++ ++ /* The pretty-printer list of functions. */ ++ PyObject *printers; ++} objfile_object; ++ ++static PyTypeObject objfile_object_type; ++ ++static const struct objfile_data *objfpy_objfile_data_key; ++ ++ ++ ++/* An Objfile method which returns the objfile's file name, or None. */ ++static PyObject * ++objfpy_get_filename (PyObject *self, void *closure) ++{ ++ objfile_object *obj = (objfile_object *) self; ++ if (obj->objfile && obj->objfile->name) ++ return PyString_Decode (obj->objfile->name, strlen (obj->objfile->name), ++ host_charset (), NULL); ++ Py_RETURN_NONE; ++} ++ ++static void ++objfpy_dealloc (PyObject *o) ++{ ++ objfile_object *self = (objfile_object *) o; ++ Py_XDECREF (self->printers); ++ self->ob_type->tp_free ((PyObject *) self); ++} ++ ++static PyObject * ++objfpy_new (PyTypeObject *type, PyObject *args, PyObject *keywords) ++{ ++ objfile_object *self = (objfile_object *) type->tp_alloc (type, 0); ++ if (self) ++ { ++ self->objfile = NULL; ++ ++ self->printers = PyList_New (0); ++ if (!self->printers) ++ { ++ Py_DECREF (self); ++ return NULL; ++ } ++ } ++ return (PyObject *) self; ++} ++ ++PyObject * ++objfpy_get_printers (PyObject *o, void *ignore) ++{ ++ objfile_object *self = (objfile_object *) o; ++ Py_INCREF (self->printers); ++ return self->printers; ++} ++ ++static int ++objfpy_set_printers (PyObject *o, PyObject *value, void *ignore) ++{ ++ objfile_object *self = (objfile_object *) o; ++ if (! value) ++ { ++ PyErr_SetString (PyExc_TypeError, ++ "cannot delete the pretty_printers attribute"); ++ return -1; ++ } ++ ++ if (! PyList_Check (value)) ++ { ++ PyErr_SetString (PyExc_TypeError, ++ "the pretty_printers attribute must be a list"); ++ return -1; ++ } ++ ++ Py_XDECREF (self->printers); ++ Py_INCREF (value); ++ self->printers = value; ++ ++ return 0; ++} ++ ++ ++ ++/* Clear the OBJFILE pointer in an Objfile object and remove the ++ reference. */ ++static void ++clean_up_objfile (struct objfile *objfile, void *datum) ++{ ++ objfile_object *object = datum; ++ object->objfile = NULL; ++ Py_DECREF ((PyObject *) object); ++} ++ ++/* Return the Python object of type Objfile representing OBJFILE. If ++ the object has already been created, return it. Otherwise, create ++ it. Return NULL and set the Python error on failure. */ ++PyObject * ++objfile_to_objfile_object (struct objfile *objfile) ++{ ++ objfile_object *object; ++ ++ object = objfile_data (objfile, objfpy_objfile_data_key); ++ if (!object) ++ { ++ object = PyObject_New (objfile_object, &objfile_object_type); ++ if (object) ++ { ++ PyObject *dict; ++ ++ object->objfile = objfile; ++ ++ object->printers = PyList_New (0); ++ if (!object->printers) ++ { ++ Py_DECREF (object); ++ return NULL; ++ } ++ ++ set_objfile_data (objfile, objfpy_objfile_data_key, object); ++ } ++ } ++ ++ return (PyObject *) object; ++} ++ ++void ++gdbpy_initialize_objfile (void) ++{ ++ objfpy_objfile_data_key ++ = register_objfile_data_with_cleanup (clean_up_objfile); ++ ++ if (PyType_Ready (&objfile_object_type) < 0) ++ return; ++ ++ Py_INCREF (&objfile_object_type); ++ PyModule_AddObject (gdb_module, "Objfile", (PyObject *) &objfile_object_type); ++} ++ ++ ++ ++static PyGetSetDef objfile_getset[] = ++{ ++ { "filename", objfpy_get_filename, NULL, ++ "The objfile's filename, or None.", NULL }, ++ { "pretty_printers", objfpy_get_printers, objfpy_set_printers, ++ "Pretty printers.", NULL }, ++ { NULL } ++}; ++ ++static PyTypeObject objfile_object_type = ++{ ++ PyObject_HEAD_INIT (NULL) ++ 0, /*ob_size*/ ++ "gdb.Objfile", /*tp_name*/ ++ sizeof (objfile_object), /*tp_basicsize*/ ++ 0, /*tp_itemsize*/ ++ objfpy_dealloc, /*tp_dealloc*/ ++ 0, /*tp_print*/ ++ 0, /*tp_getattr*/ ++ 0, /*tp_setattr*/ ++ 0, /*tp_compare*/ ++ 0, /*tp_repr*/ ++ 0, /*tp_as_number*/ ++ 0, /*tp_as_sequence*/ ++ 0, /*tp_as_mapping*/ ++ 0, /*tp_hash */ ++ 0, /*tp_call*/ ++ 0, /*tp_str*/ ++ 0, /*tp_getattro*/ ++ 0, /*tp_setattro*/ ++ 0, /*tp_as_buffer*/ ++ Py_TPFLAGS_DEFAULT, /*tp_flags*/ ++ "GDB objfile object", /* tp_doc */ ++ 0, /* tp_traverse */ ++ 0, /* tp_clear */ ++ 0, /* tp_richcompare */ ++ 0, /* tp_weaklistoffset */ ++ 0, /* tp_iter */ ++ 0, /* tp_iternext */ ++ 0, /* tp_methods */ ++ 0, /* tp_members */ ++ objfile_getset, /* tp_getset */ ++ 0, /* tp_base */ ++ 0, /* tp_dict */ ++ 0, /* tp_descr_get */ ++ 0, /* tp_descr_set */ ++ 0, /* tp_dictoffset */ ++ 0, /* tp_init */ ++ 0, /* tp_alloc */ ++ objfpy_new, /* tp_new */ ++}; +diff --git a/gdb/python/python-param.c b/gdb/python/python-param.c +new file mode 100644 +index 0000000..1f591a8 +--- /dev/null ++++ b/gdb/python/python-param.c +@@ -0,0 +1,606 @@ ++/* gdb parameters implemented in Python ++ ++ Copyright (C) 2008, 2009 Free Software Foundation, Inc. ++ ++ This file is part of GDB. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++ ++#include "defs.h" ++#include "value.h" ++#include "exceptions.h" ++#include "python-internal.h" ++#include "charset.h" ++#include "gdbcmd.h" ++#include "cli/cli-decode.h" ++#include "completer.h" ++ ++/* Parameter constants and their values. */ ++struct parm_constant ++{ ++ char *name; ++ int value; ++}; ++ ++struct parm_constant parm_constants[] = ++{ ++ { "PARAM_BOOLEAN", var_boolean }, ++ { "PARAM_AUTO_BOOLEAN", var_auto_boolean }, ++ { "PARAM_UINTEGER", var_uinteger }, ++ { "PARAM_INTEGER", var_integer }, ++ { "PARAM_STRING", var_string }, ++ { "PARAM_STRING_NOESCAPE", var_string_noescape }, ++ { "PARAM_OPTIONAL_FILENAME", var_optional_filename }, ++ { "PARAM_FILENAME", var_filename }, ++ { "PARAM_ZINTEGER", var_zinteger }, ++ { "PARAM_ENUM", var_enum }, ++ { NULL, 0 } ++}; ++ ++/* A union that can hold anything described by enum var_types. */ ++union parmpy_variable ++{ ++ /* Hold an integer value, for boolean and integer types. */ ++ int intval; ++ ++ /* Hold an auto_boolean. */ ++ enum auto_boolean autoboolval; ++ ++ /* Hold an unsigned integer value, for uinteger. */ ++ unsigned int uintval; ++ ++ /* Hold a string, for the various string types. */ ++ char *stringval; ++ ++ /* Hold a string, for enums. */ ++ const char *cstringval; ++}; ++ ++/* A gdb parameter. */ ++struct parmpy_object ++{ ++ PyObject_HEAD ++ ++ /* The type of the parameter. */ ++ enum var_types type; ++ ++ /* The value of the parameter. */ ++ union parmpy_variable value; ++ ++ /* For an enum command, the possible values. The vector is ++ allocated with xmalloc, as is each element. It is ++ NULL-terminated. */ ++ const char **enumeration; ++}; ++ ++typedef struct parmpy_object parmpy_object; ++ ++static PyTypeObject parmpy_object_type; ++ ++/* Some handy string constants. */ ++static PyObject *set_doc_cst; ++static PyObject *show_doc_cst; ++ ++ ++ ++/* Get an attribute. */ ++static PyObject * ++get_attr (PyObject *obj, PyObject *attr_name) ++{ ++ if (PyString_Check (attr_name) ++ && ! strcmp (PyString_AsString (attr_name), "value")) ++ { ++ parmpy_object *self = (parmpy_object *) obj; ++ return gdbpy_parameter_value (self->type, &self->value); ++ } ++ ++ return PyObject_GenericGetAttr (obj, attr_name); ++} ++ ++/* Set a parameter value from a Python value. Return 0 on success, -1 ++ on failure. */ ++static int ++set_parameter_value (parmpy_object *self, PyObject *value) ++{ ++ int cmp; ++ ++ switch (self->type) ++ { ++ case var_string: ++ case var_string_noescape: ++ case var_optional_filename: ++ case var_filename: ++ if (! gdbpy_is_string (value) ++ && (self->type == var_filename ++ || value != Py_None)) ++ { ++ PyErr_SetString (PyExc_RuntimeError, "string required"); ++ return -1; ++ } ++ if (self->value.stringval) ++ xfree (self->value.stringval); ++ if (value == Py_None) ++ { ++ if (self->type == var_optional_filename) ++ self->value.stringval = xstrdup (""); ++ else ++ self->value.stringval = NULL; ++ } ++ else ++ self->value.stringval = python_string_to_host_string (value); ++ break; ++ ++ case var_enum: ++ { ++ int i; ++ char *str; ++ ++ if (! gdbpy_is_string (value)) ++ { ++ PyErr_SetString (PyExc_RuntimeError, "string required"); ++ return -1; ++ } ++ ++ str = python_string_to_host_string (value); ++ for (i = 0; self->enumeration[i]; ++i) ++ if (! strcmp (self->enumeration[i], str)) ++ break; ++ xfree (str); ++ if (! self->enumeration[i]) ++ { ++ PyErr_SetString (PyExc_RuntimeError, ++ "value must be member of enumeration"); ++ return -1; ++ } ++ self->value.cstringval = self->enumeration[i]; ++ break; ++ } ++ ++ case var_boolean: ++ if (! PyBool_Check (value)) ++ { ++ PyErr_SetString (PyExc_RuntimeError, "boolean required"); ++ return -1; ++ } ++ cmp = PyObject_IsTrue (value); ++ if (cmp < 0) ++ return -1; ++ self->value.intval = cmp; ++ break; ++ ++ case var_auto_boolean: ++ if (! PyBool_Check (value) && value != Py_None) ++ { ++ PyErr_SetString (PyExc_RuntimeError, ++ "boolean or None required"); ++ return -1; ++ } ++ ++ if (value == Py_None) ++ self->value.autoboolval = AUTO_BOOLEAN_AUTO; ++ else ++ { ++ cmp = PyObject_IsTrue (value); ++ if (cmp < 0 ) ++ return -1; ++ if (cmp == 1) ++ self->value.autoboolval = AUTO_BOOLEAN_TRUE; ++ else ++ self->value.autoboolval = AUTO_BOOLEAN_FALSE; ++ ++ break; ++ } ++ ++ case var_integer: ++ case var_zinteger: ++ case var_uinteger: ++ { ++ long l; ++ int ok; ++ ++ if (! PyInt_Check (value)) ++ { ++ PyErr_SetString (PyExc_RuntimeError, "value must be integer"); ++ return -1; ++ } ++ ++ l = PyInt_AsLong (value); ++ if (self->type == var_uinteger) ++ { ++ ok = (l >= 0 && l <= UINT_MAX); ++ if (l == 0) ++ l = UINT_MAX; ++ } ++ else if (self->type == var_integer) ++ { ++ ok = (l >= INT_MIN && l <= INT_MAX); ++ if (l == 0) ++ l = INT_MAX; ++ } ++ else ++ ok = (l >= INT_MIN && l <= INT_MAX); ++ ++ if (! ok) ++ { ++ PyErr_SetString (PyExc_RuntimeError, "range exceeded"); ++ return -1; ++ } ++ ++ self->value.intval = (int) l; ++ break; ++ } ++ ++ default: ++ PyErr_SetString (PyExc_RuntimeError, "programmer error: unhandled type"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++/* Set an attribute. */ ++static int ++set_attr (PyObject *obj, PyObject *attr_name, PyObject *val) ++{ ++ if (PyString_Check (attr_name) ++ && ! strcmp (PyString_AsString (attr_name), "value")) ++ { ++ if (!val) ++ { ++ PyErr_SetString (PyExc_RuntimeError, ++ "cannot delete a parameter's value"); ++ return -1; ++ } ++ return set_parameter_value ((parmpy_object *) obj, val); ++ } ++ ++ return PyObject_GenericSetAttr (obj, attr_name, val); ++} ++ ++ ++ ++/* A helper function that dispatches to the appropriate add_setshow ++ function. */ ++static void ++add_setshow_generic (int parmclass, enum command_class cmdclass, ++ char *cmd_name, parmpy_object *self, ++ char *set_doc, char *show_doc, char *help_doc, ++ struct cmd_list_element **set_list, ++ struct cmd_list_element **show_list) ++{ ++ switch (parmclass) ++ { ++ case var_boolean: ++ add_setshow_boolean_cmd (cmd_name, cmdclass, &self->value.intval, ++ set_doc, show_doc, help_doc, ++ NULL, NULL, set_list, show_list); ++ break; ++ ++ case var_auto_boolean: ++ add_setshow_auto_boolean_cmd (cmd_name, cmdclass, ++ &self->value.autoboolval, ++ set_doc, show_doc, help_doc, ++ NULL, NULL, set_list, show_list); ++ break; ++ ++ case var_uinteger: ++ add_setshow_uinteger_cmd (cmd_name, cmdclass, &self->value.uintval, ++ set_doc, show_doc, help_doc, ++ NULL, NULL, set_list, show_list); ++ break; ++ ++ case var_integer: ++ add_setshow_integer_cmd (cmd_name, cmdclass, &self->value.intval, ++ set_doc, show_doc, help_doc, ++ NULL, NULL, set_list, show_list); ++ break; ++ ++ case var_string: ++ add_setshow_string_cmd (cmd_name, cmdclass, &self->value.stringval, ++ set_doc, show_doc, help_doc, ++ NULL, NULL, set_list, show_list); ++ break; ++ ++ case var_string_noescape: ++ add_setshow_string_noescape_cmd (cmd_name, cmdclass, ++ &self->value.stringval, ++ set_doc, show_doc, help_doc, ++ NULL, NULL, set_list, show_list); ++ break; ++ ++ case var_optional_filename: ++ add_setshow_optional_filename_cmd (cmd_name, cmdclass, ++ &self->value.stringval, ++ set_doc, show_doc, help_doc, ++ NULL, NULL, set_list, show_list); ++ break; ++ ++ case var_filename: ++ add_setshow_filename_cmd (cmd_name, cmdclass, &self->value.stringval, ++ set_doc, show_doc, help_doc, ++ NULL, NULL, set_list, show_list); ++ break; ++ ++ case var_zinteger: ++ add_setshow_zinteger_cmd (cmd_name, cmdclass, &self->value.intval, ++ set_doc, show_doc, help_doc, ++ NULL, NULL, set_list, show_list); ++ break; ++ ++ case var_enum: ++ add_setshow_enum_cmd (cmd_name, cmdclass, self->enumeration, ++ &self->value.cstringval, ++ set_doc, show_doc, help_doc, ++ NULL, NULL, set_list, show_list); ++ /* Initialize the value, just in case. */ ++ self->value.cstringval = self->enumeration[0]; ++ break; ++ } ++} ++ ++/* A helper which computes enum values. Returns 1 on success, 0 on ++ error. */ ++static int ++compute_enum_values (parmpy_object *self, PyObject *enum_values) ++{ ++ Py_ssize_t size, i; ++ ++ if (! enum_values) ++ { ++ PyErr_SetString (PyExc_RuntimeError, ++ "enumeration required for PARAM_ENUM"); ++ return 0; ++ } ++ ++ if (! PySequence_Check (enum_values)) ++ { ++ PyErr_SetString (PyExc_RuntimeError, "enumeration is not a sequence"); ++ return 0; ++ } ++ ++ size = PySequence_Size (enum_values); ++ if (size < 0) ++ return 0; ++ if (size == 0) ++ { ++ PyErr_SetString (PyExc_RuntimeError, "empty enumeration"); ++ return 0; ++ } ++ ++ self->enumeration = xmalloc ((size + 1) * sizeof (char *)); ++ memset (self->enumeration, 0, (size + 1) * sizeof (char *)); ++ ++ for (i = 0; i < size; ++i) ++ { ++ PyObject *item = PySequence_GetItem (enum_values, i); ++ if (! item) ++ return 0; ++ if (! gdbpy_is_string (item)) ++ { ++ PyErr_SetString (PyExc_RuntimeError, "enumeration item not a string"); ++ return 0; ++ } ++ self->enumeration[i] = python_string_to_host_string (item); ++ } ++ ++ return 1; ++} ++ ++/* A helper function which returns a documentation string for an ++ object. */ ++static char * ++get_doc_string (PyObject *object, PyObject *attr) ++{ ++ char *result = NULL; ++ if (PyObject_HasAttr (object, attr)) ++ { ++ PyObject *ds_obj = PyObject_GetAttr (object, attr); ++ if (ds_obj && gdbpy_is_string (ds_obj)) ++ result = python_string_to_host_string (ds_obj); ++ } ++ if (! result) ++ result = xstrdup ("This command is not documented."); ++ return result; ++} ++ ++/* Object initializer; sets up gdb-side structures for command. ++ ++ Use: __init__(NAME, CMDCLASS, PARMCLASS, [ENUM]) ++ ++ NAME is the name of the parameter. It may consist of multiple ++ words, in which case the final word is the name of the new command, ++ and earlier words must be prefix commands. ++ ++ CMDCLASS is the kind of command. It should be one of the COMMAND_* ++ constants defined in the gdb module. ++ ++ PARMCLASS is the type of the parameter. It should be one of the ++ PARAM_* constants defined in the gdb module. ++ ++ If PARMCLASS is PARAM_ENUM, then the final argument should be a ++ collection of strings. These strings are the valid values for this ++ parameter. ++ ++ The documentation for the parameter is taken from the doc string ++ for the python class. ++ ++*/ ++static int ++parmpy_init (PyObject *self, PyObject *args, PyObject *kwds) ++{ ++ parmpy_object *obj = (parmpy_object *) self; ++ char *name; ++ char *set_doc, *show_doc, *doc; ++ char *cmd_name; ++ int parmclass, cmdtype; ++ PyObject *enum_values = NULL; ++ struct cmd_list_element *cmd_list; ++ struct cmd_list_element **set_list, **show_list; ++ volatile struct gdb_exception except; ++ ++ if (! PyArg_ParseTuple (args, "sii|O", &name, &cmdtype, &parmclass, ++ &enum_values)) ++ return -1; ++ ++ if (cmdtype != no_class && cmdtype != class_run ++ && cmdtype != class_vars && cmdtype != class_stack ++ && cmdtype != class_files && cmdtype != class_support ++ && cmdtype != class_info && cmdtype != class_breakpoint ++ && cmdtype != class_trace && cmdtype != class_obscure ++ && cmdtype != class_maintenance) ++ { ++ PyErr_Format (PyExc_RuntimeError, "invalid command class argument"); ++ return -1; ++ } ++ ++ if (parmclass != var_boolean && parmclass != var_auto_boolean ++ && parmclass != var_uinteger && parmclass != var_integer ++ && parmclass != var_string && parmclass != var_string_noescape ++ && parmclass != var_optional_filename && parmclass != var_filename ++ && parmclass != var_zinteger && parmclass != var_enum) ++ { ++ PyErr_SetString (PyExc_RuntimeError, "invalid parameter class argument"); ++ return -1; ++ } ++ ++ if (enum_values && parmclass != var_enum) ++ { ++ PyErr_SetString (PyExc_RuntimeError, ++ "only PARAM_ENUM accepts a fourth argument"); ++ return -1; ++ } ++ if (parmclass == var_enum) ++ { ++ if (! compute_enum_values (obj, enum_values)) ++ return -1; ++ } ++ ++ obj->type = (enum var_types) parmclass; ++ memset (&obj->value, 0, sizeof (obj->value)); ++ obj->enumeration = NULL; ++ ++ cmd_name = gdbpy_parse_command_name (name, &set_list, &setlist); ++ if (! cmd_name) ++ return -1; ++ xfree (cmd_name); ++ cmd_name = gdbpy_parse_command_name (name, &show_list, &showlist); ++ if (! cmd_name) ++ return -1; ++ ++ /* FIXME: there is no way to register a destructor function for ++ set/show commands. So, these are leaked. */ ++ set_doc = get_doc_string (self, set_doc_cst); ++ show_doc = get_doc_string (self, show_doc_cst); ++ doc = get_doc_string (self, gdbpy_doc_cst); ++ ++ Py_INCREF (self); ++ ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ add_setshow_generic (parmclass, (enum command_class) cmdtype, ++ cmd_name, obj, ++ set_doc, show_doc, ++ doc, set_list, show_list); ++ } ++ if (except.reason < 0) ++ { ++ xfree (cmd_name); ++ xfree (set_doc); ++ xfree (show_doc); ++ xfree (doc); ++ Py_DECREF (self); ++ PyErr_Format (except.reason == RETURN_QUIT ++ ? PyExc_KeyboardInterrupt : PyExc_RuntimeError, ++ "%s", except.message); ++ return -1; ++ } ++ return 0; ++} ++ ++ ++ ++/* Initialize the 'parameters' module. */ ++void ++gdbpy_initialize_parameters (void) ++{ ++ int i; ++ ++ if (PyType_Ready (&parmpy_object_type) < 0) ++ return; ++ ++ set_doc_cst = PyString_FromString ("set_doc"); ++ if (! set_doc_cst) ++ return; ++ show_doc_cst = PyString_FromString ("show_doc"); ++ if (! show_doc_cst) ++ return; ++ ++ for (i = 0; parm_constants[i].name; ++i) ++ { ++ if (PyModule_AddIntConstant (gdb_module, ++ parm_constants[i].name, ++ parm_constants[i].value) < 0) ++ return; ++ } ++ ++ Py_INCREF (&parmpy_object_type); ++ PyModule_AddObject (gdb_module, "Parameter", ++ (PyObject *) &parmpy_object_type); ++} ++ ++ ++ ++static PyTypeObject parmpy_object_type = ++{ ++ PyObject_HEAD_INIT (NULL) ++ 0, /*ob_size*/ ++ "gdb.Parameter", /*tp_name*/ ++ sizeof (parmpy_object), /*tp_basicsize*/ ++ 0, /*tp_itemsize*/ ++ 0, /*tp_dealloc*/ ++ 0, /*tp_print*/ ++ 0, /*tp_getattr*/ ++ 0, /*tp_setattr*/ ++ 0, /*tp_compare*/ ++ 0, /*tp_repr*/ ++ 0, /*tp_as_number*/ ++ 0, /*tp_as_sequence*/ ++ 0, /*tp_as_mapping*/ ++ 0, /*tp_hash */ ++ 0, /*tp_call*/ ++ 0, /*tp_str*/ ++ get_attr, /*tp_getattro*/ ++ set_attr, /*tp_setattro*/ ++ 0, /*tp_as_buffer*/ ++ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ ++ "GDB parameter object", /* tp_doc */ ++ 0, /* tp_traverse */ ++ 0, /* tp_clear */ ++ 0, /* tp_richcompare */ ++ 0, /* tp_weaklistoffset */ ++ 0, /* tp_iter */ ++ 0, /* tp_iternext */ ++ 0, /* tp_methods */ ++ 0, /* tp_members */ ++ 0, /* tp_getset */ ++ 0, /* tp_base */ ++ 0, /* tp_dict */ ++ 0, /* tp_descr_get */ ++ 0, /* tp_descr_set */ ++ 0, /* tp_dictoffset */ ++ parmpy_init, /* tp_init */ ++ 0, /* tp_alloc */ ++ PyType_GenericNew /* tp_new */ ++}; +diff --git a/gdb/python/python-symbol.c b/gdb/python/python-symbol.c +new file mode 100644 +index 0000000..c7fda5c +--- /dev/null ++++ b/gdb/python/python-symbol.c +@@ -0,0 +1,337 @@ ++/* Python interface to symbols. ++ ++ Copyright (C) 2008 Free Software Foundation, Inc. ++ ++ This file is part of GDB. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++#include "defs.h" ++#include "block.h" ++#include "exceptions.h" ++#include "frame.h" ++#include "symtab.h" ++#include "python-internal.h" ++ ++typedef struct { ++ PyObject_HEAD ++ struct symbol *symbol; ++} symbol_object; ++ ++ ++static PyObject * ++sympy_str (PyObject *self) ++{ ++ int ret; ++ char *s; ++ PyObject *result; ++ ++ ret = asprintf (&s, "symbol for %s", ++ SYMBOL_PRINT_NAME (((symbol_object *) self)->symbol)); ++ if (ret < 0) ++ Py_RETURN_NONE; ++ ++ result = PyString_FromString (s); ++ xfree (s); ++ ++ return result; ++} ++ ++static PyObject * ++sympy_get_value (PyObject *self, void *closure) ++{ ++ symbol_object *self_sym = (symbol_object *) self; ++ ++ switch (SYMBOL_CLASS (self_sym->symbol)) ++ { ++ case LOC_BLOCK: ++ return block_to_block_object (SYMBOL_BLOCK_VALUE (self_sym->symbol)); ++ } ++ ++ PyErr_SetString (PyExc_NotImplementedError, ++ "Symbol type not yet supported in Python scripts."); ++ return NULL; ++} ++ ++static PyObject * ++sympy_get_symtab (PyObject *self, void *closure) ++{ ++ symbol_object *self_sym = (symbol_object *) self; ++ ++ return symtab_to_symtab_object (SYMBOL_SYMTAB (self_sym->symbol)); ++} ++ ++static PyObject * ++sympy_get_name (PyObject *self, void *closure) ++{ ++ symbol_object *self_sym = (symbol_object *) self; ++ ++ return PyString_FromString (SYMBOL_NATURAL_NAME (self_sym->symbol)); ++} ++ ++static PyObject * ++sympy_get_linkage_name (PyObject *self, void *closure) ++{ ++ symbol_object *self_sym = (symbol_object *) self; ++ ++ return PyString_FromString (SYMBOL_LINKAGE_NAME (self_sym->symbol)); ++} ++ ++static PyObject * ++sympy_get_print_name (PyObject *self, void *closure) ++{ ++ symbol_object *self_sym = (symbol_object *) self; ++ ++ return PyString_FromString (SYMBOL_PRINT_NAME (self_sym->symbol)); ++} ++ ++static PyObject * ++sympy_get_addr_class (PyObject *self, void *closure) ++{ ++ symbol_object *self_sym = (symbol_object *) self; ++ ++ return PyInt_FromLong (SYMBOL_CLASS (self_sym->symbol)); ++} ++ ++static PyObject * ++sympy_is_argument (PyObject *self, void *closure) ++{ ++ symbol_object *self_sym = (symbol_object *) self; ++ ++ return PyBool_FromLong (SYMBOL_IS_ARGUMENT (self_sym->symbol)); ++} ++ ++static PyObject * ++sympy_is_constant (PyObject *self, void *closure) ++{ ++ symbol_object *self_sym = (symbol_object *) self; ++ enum address_class class = SYMBOL_CLASS (self_sym->symbol); ++ ++ return PyBool_FromLong (class == LOC_CONST || class == LOC_CONST_BYTES); ++} ++ ++static PyObject * ++sympy_is_function (PyObject *self, void *closure) ++{ ++ symbol_object *self_sym = (symbol_object *) self; ++ enum address_class class = SYMBOL_CLASS (self_sym->symbol); ++ ++ return PyBool_FromLong (class == LOC_BLOCK); ++} ++ ++static PyObject * ++sympy_is_variable (PyObject *self, void *closure) ++{ ++ symbol_object *self_sym = (symbol_object *) self; ++ enum address_class class = SYMBOL_CLASS (self_sym->symbol); ++ ++ return PyBool_FromLong (!SYMBOL_IS_ARGUMENT (self_sym->symbol) ++ && (class == LOC_LOCAL || class == LOC_REGISTER || class == LOC_STATIC ++ || class == LOC_COMPUTED || class == LOC_OPTIMIZED_OUT)); ++} ++ ++PyObject * ++symbol_to_symbol_object (struct symbol *sym) ++{ ++ symbol_object *sym_obj; ++ ++ sym_obj = PyObject_New (symbol_object, &symbol_object_type); ++ if (sym_obj == NULL) ++ { ++ PyErr_SetString (PyExc_MemoryError, "Could not allocate symbol object."); ++ return NULL; ++ } ++ ++ sym_obj->symbol = sym; ++ ++ return (PyObject *) sym_obj; ++} ++ ++struct symbol * ++symbol_object_to_symbol (PyObject *obj) ++{ ++ if (! PyObject_TypeCheck (obj, &symbol_object_type)) ++ return NULL; ++ return ((symbol_object *) obj)->symbol; ++} ++ ++/* Implementation of ++ gdb.lookup_symbol (name [, block] [, domain]) -> (symbol, is_field_of_this) ++ A tuple with 2 elements is always returned. The first is the symbol ++ object or None, the second is a boolean with the value of ++ is_a_field_of_this (see comment in lookup_symbol_in_language). */ ++ ++PyObject *gdbpy_lookup_symbol (PyObject *self, PyObject *args, PyObject *kw) ++{ ++ int domain = VAR_DOMAIN, is_a_field_of_this = 0; ++ const char *name; ++ static char *keywords[] = { "name", "block", "domain", NULL }; ++ struct symbol *symbol; ++ PyObject *block_obj = NULL, *ret_tuple, *sym_obj, *bool_obj; ++ struct block *block = NULL; ++ ++ if (! PyArg_ParseTupleAndKeywords (args, kw, "s|O!i", keywords, &name, ++ &block_object_type, &block_obj, &domain)) ++ return NULL; ++ ++ if (block_obj) ++ block = block_object_to_block (block_obj); ++ else ++ { ++ struct frame_info *selected_frame; ++ volatile struct gdb_exception except; ++ ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ selected_frame = get_selected_frame (_("No frame selected.")); ++ block = block_for_pc (get_frame_address_in_block (selected_frame)); ++ } ++ GDB_PY_HANDLE_EXCEPTION (except); ++ } ++ ++ symbol = lookup_symbol (name, block, domain, &is_a_field_of_this); ++ ++ ret_tuple = PyTuple_New (2); ++ if (!ret_tuple) ++ { ++ PyErr_SetString (PyExc_MemoryError, "Could not allocate tuple object."); ++ return NULL; ++ } ++ ++ if (symbol) ++ { ++ sym_obj = symbol_to_symbol_object (symbol); ++ if (!sym_obj) ++ { ++ Py_DECREF (ret_tuple); ++ return NULL; ++ } ++ } ++ else ++ { ++ sym_obj = Py_None; ++ Py_INCREF (Py_None); ++ } ++ PyTuple_SET_ITEM (ret_tuple, 0, sym_obj); ++ ++ bool_obj = is_a_field_of_this? Py_True : Py_False; ++ Py_INCREF (bool_obj); ++ PyTuple_SET_ITEM (ret_tuple, 1, bool_obj); ++ ++ return ret_tuple; ++} ++ ++void ++gdbpy_initialize_symbols (void) ++{ ++ symbol_object_type.tp_new = PyType_GenericNew; ++ if (PyType_Ready (&symbol_object_type) < 0) ++ return; ++ ++ /* FIXME: These would probably be best exposed as class attributes of Symbol, ++ but I don't know how to do it except by messing with the type's dictionary. ++ That seems too messy. */ ++ /* FIXME 2: Some of these were removed from GDB since I first wrote this code, ++ so it's probably a good idea not to expose them to Python. */ ++ PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_UNDEF", LOC_UNDEF); ++ PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_CONST", LOC_CONST); ++ PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_STATIC", LOC_STATIC); ++ PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_REGISTER", LOC_REGISTER); ++ PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_ARG", LOC_ARG); ++ PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_REF_ARG", LOC_REF_ARG); ++ PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_LOCAL", LOC_LOCAL); ++ PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_TYPEDEF", LOC_TYPEDEF); ++ PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_LABEL", LOC_LABEL); ++ PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_BLOCK", LOC_BLOCK); ++ PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_CONST_BYTES", ++ LOC_CONST_BYTES); ++ PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_UNRESOLVED", LOC_UNRESOLVED); ++ PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_OPTIMIZED_OUT", ++ LOC_OPTIMIZED_OUT); ++ PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_COMPUTED", LOC_COMPUTED); ++ PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_REGPARM_ADDR", ++ LOC_REGPARM_ADDR); ++ PyModule_AddIntConstant (gdb_module, "SYMBOL_UNDEF_DOMAIN", UNDEF_DOMAIN); ++ PyModule_AddIntConstant (gdb_module, "SYMBOL_VAR_DOMAIN", VAR_DOMAIN); ++ PyModule_AddIntConstant (gdb_module, "SYMBOL_STRUCT_DOMAIN", STRUCT_DOMAIN); ++ PyModule_AddIntConstant (gdb_module, "SYMBOL_LABEL_DOMAIN", LABEL_DOMAIN); ++ PyModule_AddIntConstant (gdb_module, "SYMBOL_VARIABLES_DOMAIN", ++ VARIABLES_DOMAIN); ++ PyModule_AddIntConstant (gdb_module, "SYMBOL_FUNCTIONS_DOMAIN", ++ FUNCTIONS_DOMAIN); ++ PyModule_AddIntConstant (gdb_module, "SYMBOL_TYPES_DOMAIN", TYPES_DOMAIN); ++ ++ Py_INCREF (&symbol_object_type); ++ PyModule_AddObject (gdb_module, "Symbol", (PyObject *) &symbol_object_type); ++} ++ ++ ++ ++static PyGetSetDef symbol_object_getset[] = { ++ { "value", sympy_get_value, NULL, "Value of the symbol.", NULL }, ++ { "symtab", sympy_get_symtab, NULL, ++ "Symbol table in which the symbol appears.", NULL }, ++ { "name", sympy_get_name, NULL, ++ "Name of the symbol, as it appears in the source code.", NULL }, ++ { "linkage_name", sympy_get_linkage_name, NULL, ++ "Name of the symbol, as used by the linker (i.e., may be mangled).", NULL }, ++ { "print_name", sympy_get_print_name, NULL, ++ "Name of the symbol in a form suitable for output.\n\ ++This is either name or linkage_name, depending on whether the user asked GDB\n\ ++to display demangled or mangled names.", NULL }, ++ { "addr_class", sympy_get_addr_class, NULL, "Address class of the symbol." }, ++ { "is_argument", sympy_is_argument, NULL, ++ "True if the symbol is an argument of a function." }, ++ { "is_constant", sympy_is_constant, NULL, ++ "True if the symbol is a constant." }, ++ { "is_function", sympy_is_function, NULL, ++ "True if the symbol is a function or method." }, ++ { "is_variable", sympy_is_variable, NULL, ++ "True if the symbol is a variable." }, ++ { NULL } /* Sentinel */ ++}; ++ ++PyTypeObject symbol_object_type = { ++ PyObject_HEAD_INIT (NULL) ++ 0, /*ob_size*/ ++ "gdb.Symbol", /*tp_name*/ ++ sizeof (symbol_object), /*tp_basicsize*/ ++ 0, /*tp_itemsize*/ ++ 0, /*tp_dealloc*/ ++ 0, /*tp_print*/ ++ 0, /*tp_getattr*/ ++ 0, /*tp_setattr*/ ++ 0, /*tp_compare*/ ++ 0, /*tp_repr*/ ++ 0, /*tp_as_number*/ ++ 0, /*tp_as_sequence*/ ++ 0, /*tp_as_mapping*/ ++ 0, /*tp_hash */ ++ 0, /*tp_call*/ ++ sympy_str, /*tp_str*/ ++ 0, /*tp_getattro*/ ++ 0, /*tp_setattro*/ ++ 0, /*tp_as_buffer*/ ++ Py_TPFLAGS_DEFAULT, /*tp_flags*/ ++ "GDB symbol object", /* tp_doc */ ++ 0, /* tp_traverse */ ++ 0, /* tp_clear */ ++ 0, /* tp_richcompare */ ++ 0, /* tp_weaklistoffset */ ++ 0, /* tp_iter */ ++ 0, /* tp_iternext */ ++ 0, /* tp_methods */ ++ 0, /* tp_members */ ++ symbol_object_getset /* tp_getset */ ++}; +diff --git a/gdb/python/python-symtab.c b/gdb/python/python-symtab.c +new file mode 100644 +index 0000000..a48c38c +--- /dev/null ++++ b/gdb/python/python-symtab.c +@@ -0,0 +1,311 @@ ++/* Python interface to symbol tables. ++ ++ Copyright (C) 2008 Free Software Foundation, Inc. ++ ++ This file is part of GDB. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++#include "defs.h" ++#include "charset.h" ++#include "symtab.h" ++#include "source.h" ++#include "python-internal.h" ++ ++typedef struct { ++ PyObject_HEAD ++ struct symtab *symtab; ++} symtab_object; ++ ++static PyTypeObject symtab_object_type; ++ ++typedef struct { ++ PyObject_HEAD ++ symtab_object *symtab; ++ struct symtab_and_line *sal; ++} sal_object; ++ ++static PyTypeObject sal_object_type; ++ ++ ++static PyObject * ++stpy_str (PyObject *self) ++{ ++ int ret; ++ char *s; ++ PyObject *result; ++ ++ ret = asprintf (&s, "symbol table for %s", ++ ((symtab_object *) self)->symtab->filename); ++ if (ret < 0) ++ Py_RETURN_NONE; ++ ++ result = PyString_FromString (s); ++ xfree (s); ++ ++ return result; ++} ++ ++static PyObject * ++stpy_get_filename (PyObject *self, void *closure) ++{ ++ symtab_object *self_symtab = (symtab_object *) self; ++ PyObject *str_obj; ++ ++ /* FIXME: Can symtab->filename really be NULL? */ ++ if (self_symtab->symtab->filename) ++ str_obj = PyString_Decode (self_symtab->symtab->filename, ++ strlen (self_symtab->symtab->filename), ++ host_charset (), NULL); ++ else ++ { ++ str_obj = Py_None; ++ Py_INCREF (Py_None); ++ } ++ ++ return str_obj; ++} ++ ++static PyObject * ++stpy_fullname (PyObject *self, PyObject *args) ++{ ++ char *fullname; ++ ++ fullname = symtab_to_fullname (((symtab_object *) self)->symtab); ++ if (fullname) ++ return PyString_Decode (fullname, strlen (fullname), host_charset (), NULL); ++ ++ Py_RETURN_NONE; ++} ++ ++static PyObject * ++salpy_str (PyObject *self) ++{ ++ int ret; ++ char *s, *filename; ++ sal_object *sal_obj; ++ PyObject *result; ++ ++ sal_obj = (sal_object *) self; ++ filename = (sal_obj->symtab == (symtab_object *) Py_None)? "" : ++ sal_obj->symtab->symtab->filename; ++ ret = asprintf (&s, "symbol and line for %s, line %d", filename, ++ sal_obj->sal->line); ++ if (ret < 0) ++ Py_RETURN_NONE; ++ ++ result = PyString_FromString (s); ++ xfree (s); ++ ++ return result; ++} ++ ++static PyObject * ++salpy_get_pc (PyObject *self, void *closure) ++{ ++ return PyLong_FromUnsignedLongLong (((sal_object *) self)->sal->pc); ++} ++ ++static PyObject * ++salpy_get_line (PyObject *self, void *closure) ++{ ++ return PyLong_FromUnsignedLongLong (((sal_object *) self)->sal->line); ++} ++ ++static PyObject * ++salpy_get_symtab (PyObject *self, void *closure) ++{ ++ sal_object *self_sal = (sal_object *) self; ++ ++ Py_INCREF (self_sal->symtab); ++ ++ return (PyObject *) self_sal->symtab; ++} ++ ++static void ++salpy_dealloc (PyObject *self) ++{ ++ sal_object *self_sal = (sal_object *) self; ++ ++ Py_DECREF (self_sal->symtab); ++ xfree (self_sal->sal); ++ self_sal->ob_type->tp_free (self); ++} ++ ++PyObject * ++symtab_and_line_to_sal_object (struct symtab_and_line sal) ++{ ++ sal_object *sal_obj; ++ symtab_object *symtab_obj; ++ ++ sal_obj = PyObject_New (sal_object, &sal_object_type); ++ if (sal_obj == NULL) ++ { ++ PyErr_SetString (PyExc_MemoryError, ++ "Could not allocate Symtab_and_line object."); ++ return NULL; ++ } ++ ++ if (sal.symtab) ++ { ++ symtab_obj = (symtab_object *) symtab_to_symtab_object (sal.symtab); ++ if (symtab_obj == NULL) ++ { ++ Py_DECREF (sal_obj); ++ return NULL; ++ } ++ ++ symtab_obj->symtab = sal.symtab; ++ } ++ else ++ { ++ symtab_obj = (symtab_object *) Py_None; ++ Py_INCREF (Py_None); ++ } ++ ++ sal_obj->sal = (struct symtab_and_line *) ++ xmalloc (sizeof (struct symtab_and_line)); ++ *(sal_obj->sal) = sal; ++ sal_obj->symtab = symtab_obj; ++ ++ return (PyObject *) sal_obj; ++} ++ ++PyObject * ++symtab_to_symtab_object (struct symtab *symtab) ++{ ++ symtab_object *symtab_obj; ++ ++ symtab_obj = PyObject_New (symtab_object, &symtab_object_type); ++ if (symtab_obj == NULL) ++ { ++ PyErr_SetString (PyExc_MemoryError, ++ "Could not allocate Symtab object."); ++ ++ return NULL; ++ } ++ ++ symtab_obj->symtab = symtab; ++ ++ return (PyObject *) symtab_obj; ++} ++ ++void ++gdbpy_initialize_symtabs (void) ++{ ++ symtab_object_type.tp_new = PyType_GenericNew; ++ if (PyType_Ready (&symtab_object_type) < 0) ++ return; ++ ++ sal_object_type.tp_new = PyType_GenericNew; ++ if (PyType_Ready (&sal_object_type) < 0) ++ return; ++ ++ Py_INCREF (&symtab_object_type); ++ PyModule_AddObject (gdb_module, "Symtab", (PyObject *) &symtab_object_type); ++ ++ Py_INCREF (&sal_object_type); ++ PyModule_AddObject (gdb_module, "Symtab_and_line", ++ (PyObject *) &sal_object_type); ++} ++ ++ ++ ++static PyGetSetDef symtab_object_getset[] = { ++ { "filename", stpy_get_filename, NULL, ++ "The symbol table's source filename.", NULL }, ++ {NULL} /* Sentinel */ ++}; ++ ++static PyMethodDef symtab_object_methods[] = { ++ { "fullname", stpy_fullname, METH_NOARGS, ++ "Return the symtab's full source filename." }, ++ {NULL} /* Sentinel */ ++}; ++ ++static PyTypeObject symtab_object_type = { ++ PyObject_HEAD_INIT (NULL) ++ 0, /*ob_size*/ ++ "gdb.Symtab", /*tp_name*/ ++ sizeof (symtab_object), /*tp_basicsize*/ ++ 0, /*tp_itemsize*/ ++ 0, /*tp_dealloc*/ ++ 0, /*tp_print*/ ++ 0, /*tp_getattr*/ ++ 0, /*tp_setattr*/ ++ 0, /*tp_compare*/ ++ 0, /*tp_repr*/ ++ 0, /*tp_as_number*/ ++ 0, /*tp_as_sequence*/ ++ 0, /*tp_as_mapping*/ ++ 0, /*tp_hash */ ++ 0, /*tp_call*/ ++ stpy_str, /*tp_str*/ ++ 0, /*tp_getattro*/ ++ 0, /*tp_setattro*/ ++ 0, /*tp_as_buffer*/ ++ Py_TPFLAGS_DEFAULT, /*tp_flags*/ ++ "GDB symtab object", /* tp_doc */ ++ 0, /* tp_traverse */ ++ 0, /* tp_clear */ ++ 0, /* tp_richcompare */ ++ 0, /* tp_weaklistoffset */ ++ 0, /* tp_iter */ ++ 0, /* tp_iternext */ ++ symtab_object_methods, /* tp_methods */ ++ 0, /* tp_members */ ++ symtab_object_getset /* tp_getset */ ++}; ++ ++static PyGetSetDef sal_object_getset[] = { ++ { "symtab", salpy_get_symtab, NULL, "Symtab object.", NULL }, ++ { "pc", salpy_get_pc, NULL, "Return the symtab_and_line's pc.", NULL }, ++ { "line", salpy_get_line, NULL, ++ "Return the symtab_and_line's line.", NULL }, ++ {NULL} /* Sentinel */ ++}; ++ ++static PyTypeObject sal_object_type = { ++ PyObject_HEAD_INIT (NULL) ++ 0, /*ob_size*/ ++ "gdb.Symtab_and_line", /*tp_name*/ ++ sizeof (sal_object), /*tp_basicsize*/ ++ 0, /*tp_itemsize*/ ++ salpy_dealloc, /*tp_dealloc*/ ++ 0, /*tp_print*/ ++ 0, /*tp_getattr*/ ++ 0, /*tp_setattr*/ ++ 0, /*tp_compare*/ ++ 0, /*tp_repr*/ ++ 0, /*tp_as_number*/ ++ 0, /*tp_as_sequence*/ ++ 0, /*tp_as_mapping*/ ++ 0, /*tp_hash */ ++ 0, /*tp_call*/ ++ salpy_str, /*tp_str*/ ++ 0, /*tp_getattro*/ ++ 0, /*tp_setattro*/ ++ 0, /*tp_as_buffer*/ ++ Py_TPFLAGS_DEFAULT, /*tp_flags*/ ++ "GDB symtab_and_line object", /* tp_doc */ ++ 0, /* tp_traverse */ ++ 0, /* tp_clear */ ++ 0, /* tp_richcompare */ ++ 0, /* tp_weaklistoffset */ ++ 0, /* tp_iter */ ++ 0, /* tp_iternext */ ++ 0, /* tp_methods */ ++ 0, /* tp_members */ ++ sal_object_getset /* tp_getset */ ++}; +diff --git a/gdb/python/python-type.c b/gdb/python/python-type.c +new file mode 100644 +index 0000000..772a011 +--- /dev/null ++++ b/gdb/python/python-type.c +@@ -0,0 +1,821 @@ ++/* Python interface to types. ++ ++ Copyright (C) 2008, 2009 Free Software Foundation, Inc. ++ ++ This file is part of GDB. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++#include "defs.h" ++#include "value.h" ++#include "exceptions.h" ++#include "python-internal.h" ++#include "charset.h" ++#include "gdbtypes.h" ++#include "cp-support.h" ++#include "demangle.h" ++#include "objfiles.h" ++#include "gdb_assert.h" ++ ++typedef struct pyty_type_object ++{ ++ PyObject_HEAD ++ struct type *type; ++ ++ /* If a Type object is associated with an objfile, it is kept on a ++ doubly-linked list, rooted in the objfile. This lets us copy the ++ underlying struct type when the objfile is deleted. */ ++ struct pyty_type_object *prev; ++ struct pyty_type_object *next; ++} type_object; ++ ++static PyTypeObject type_object_type; ++ ++/* A Field object. */ ++typedef struct pyty_field_object ++{ ++ PyObject_HEAD ++ ++ /* Dictionary holding our attributes. */ ++ PyObject *dict; ++} field_object; ++ ++static PyTypeObject field_object_type; ++ ++/* This is used to initialize various gdb.TYPE_ constants. */ ++struct pyty_code ++{ ++ /* The code. */ ++ enum type_code code; ++ /* The name. */ ++ const char *name; ++}; ++ ++#define ENTRY(X) { X, #X } ++ ++static struct pyty_code pyty_codes[] = ++{ ++ ENTRY (TYPE_CODE_PTR), ++ ENTRY (TYPE_CODE_ARRAY), ++ ENTRY (TYPE_CODE_STRUCT), ++ ENTRY (TYPE_CODE_UNION), ++ ENTRY (TYPE_CODE_ENUM), ++ ENTRY (TYPE_CODE_FLAGS), ++ ENTRY (TYPE_CODE_FUNC), ++ ENTRY (TYPE_CODE_INT), ++ ENTRY (TYPE_CODE_FLT), ++ ENTRY (TYPE_CODE_VOID), ++ ENTRY (TYPE_CODE_SET), ++ ENTRY (TYPE_CODE_RANGE), ++ ENTRY (TYPE_CODE_STRING), ++ ENTRY (TYPE_CODE_BITSTRING), ++ ENTRY (TYPE_CODE_ERROR), ++ ENTRY (TYPE_CODE_METHOD), ++ ENTRY (TYPE_CODE_METHODPTR), ++ ENTRY (TYPE_CODE_MEMBERPTR), ++ ENTRY (TYPE_CODE_REF), ++ ENTRY (TYPE_CODE_CHAR), ++ ENTRY (TYPE_CODE_BOOL), ++ ENTRY (TYPE_CODE_COMPLEX), ++ ENTRY (TYPE_CODE_TYPEDEF), ++ ENTRY (TYPE_CODE_TEMPLATE), ++ ENTRY (TYPE_CODE_TEMPLATE_ARG), ++ ENTRY (TYPE_CODE_NAMESPACE), ++ ENTRY (TYPE_CODE_DECFLOAT), ++ ENTRY (TYPE_CODE_INTERNAL_FUNCTION), ++ { TYPE_CODE_UNDEF, NULL } ++}; ++ ++ ++ ++static void ++field_dealloc (PyObject *obj) ++{ ++ field_object *f = (field_object *) obj; ++ Py_XDECREF (f->dict); ++} ++ ++static PyObject * ++field_new (void) ++{ ++ field_object *result = PyObject_New (field_object, &field_object_type); ++ if (result) ++ { ++ result->dict = PyDict_New (); ++ if (!result->dict) ++ { ++ Py_DECREF (result); ++ result = NULL; ++ } ++ } ++ return (PyObject *) result; ++} ++ ++ ++ ++/* Return the code for this type. */ ++static PyObject * ++typy_code (PyObject *self, PyObject *args) ++{ ++ struct type *type = ((type_object *) self)->type; ++ return PyInt_FromLong (TYPE_CODE (type)); ++} ++ ++/* Helper function for typy_fields which converts a single field to a ++ dictionary. Returns NULL on error. */ ++static PyObject * ++convert_field (struct type *type, int field) ++{ ++ PyObject *result = field_new (); ++ PyObject *arg; ++ ++ if (!result) ++ return NULL; ++ ++ if (!field_is_static (&TYPE_FIELD (type, field))) ++ { ++ arg = PyLong_FromLong (TYPE_FIELD_BITPOS (type, field)); ++ if (!arg) ++ goto fail; ++ ++ if (PyObject_SetAttrString (result, "bitpos", arg) < 0) ++ goto failarg; ++ } ++ ++ if (TYPE_FIELD_NAME (type, field)) ++ arg = PyString_FromString (TYPE_FIELD_NAME (type, field)); ++ else ++ { ++ arg = Py_None; ++ Py_INCREF (arg); ++ } ++ if (!arg) ++ goto fail; ++ if (PyObject_SetAttrString (result, "name", arg) < 0) ++ goto failarg; ++ ++ arg = TYPE_FIELD_ARTIFICIAL (type, field) ? Py_True : Py_False; ++ Py_INCREF (arg); ++ if (PyObject_SetAttrString (result, "artificial", arg) < 0) ++ goto failarg; ++ ++ arg = PyLong_FromLong (TYPE_FIELD_BITSIZE (type, field)); ++ if (!arg) ++ goto fail; ++ if (PyObject_SetAttrString (result, "bitsize", arg) < 0) ++ goto failarg; ++ ++ arg = type_to_type_object (TYPE_FIELD_TYPE (type, field)); ++ if (!arg) ++ goto fail; ++ if (PyObject_SetAttrString (result, "type", arg) < 0) ++ goto failarg; ++ ++ return result; ++ ++ failarg: ++ Py_DECREF (arg); ++ fail: ++ Py_DECREF (result); ++ return NULL; ++} ++ ++/* Return a sequence of all fields. Each field is a dictionary with ++ some pre-defined keys. */ ++static PyObject * ++typy_fields (PyObject *self, PyObject *args) ++{ ++ PyObject *result; ++ int i; ++ struct type *type = ((type_object *) self)->type; ++ ++ /* We would like to make a tuple here, make fields immutable, and ++ then memoize the result (and perhaps make Field.type() lazy). ++ However, that can lead to cycles. */ ++ result = PyList_New (0); ++ ++ for (i = 0; i < TYPE_NFIELDS (type); ++i) ++ { ++ PyObject *dict = convert_field (type, i); ++ if (!dict) ++ { ++ Py_DECREF (result); ++ return NULL; ++ } ++ if (PyList_Append (result, dict)) ++ { ++ Py_DECREF (dict); ++ Py_DECREF (result); ++ return NULL; ++ } ++ } ++ ++ return result; ++} ++ ++/* Return the type's tag, or None. */ ++static PyObject * ++typy_tag (PyObject *self, PyObject *args) ++{ ++ struct type *type = ((type_object *) self)->type; ++ if (!TYPE_TAG_NAME (type)) ++ Py_RETURN_NONE; ++ return PyString_FromString (TYPE_TAG_NAME (type)); ++} ++ ++/* Return the type, stripped of typedefs. */ ++static PyObject * ++typy_strip_typedefs (PyObject *self, PyObject *args) ++{ ++ struct type *type = ((type_object *) self)->type; ++ ++ return type_to_type_object (check_typedef (type)); ++} ++ ++/* Return a Type object which represents a pointer to SELF. */ ++static PyObject * ++typy_pointer (PyObject *self, PyObject *args) ++{ ++ struct type *type = ((type_object *) self)->type; ++ volatile struct gdb_exception except; ++ ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ type = lookup_pointer_type (type); ++ } ++ GDB_PY_HANDLE_EXCEPTION (except); ++ ++ return type_to_type_object (type); ++} ++ ++/* Return a Type object which represents a reference to SELF. */ ++static PyObject * ++typy_reference (PyObject *self, PyObject *args) ++{ ++ struct type *type = ((type_object *) self)->type; ++ volatile struct gdb_exception except; ++ ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ type = lookup_reference_type (type); ++ } ++ GDB_PY_HANDLE_EXCEPTION (except); ++ ++ return type_to_type_object (type); ++} ++ ++/* Return a Type object which represents the target type of SELF. */ ++static PyObject * ++typy_target (PyObject *self, PyObject *args) ++{ ++ struct type *type = ((type_object *) self)->type; ++ ++ if (!TYPE_TARGET_TYPE (type)) ++ { ++ PyErr_SetString (PyExc_RuntimeError, "type does not have a target"); ++ return NULL; ++ } ++ ++ return type_to_type_object (TYPE_TARGET_TYPE (type)); ++} ++ ++/* Return a const-qualified type variant. */ ++static PyObject * ++typy_const (PyObject *self, PyObject *args) ++{ ++ struct type *type = ((type_object *) self)->type; ++ volatile struct gdb_exception except; ++ ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ type = make_cv_type (1, 0, type, NULL); ++ } ++ GDB_PY_HANDLE_EXCEPTION (except); ++ ++ return type_to_type_object (type); ++} ++ ++/* Return a volatile-qualified type variant. */ ++static PyObject * ++typy_volatile (PyObject *self, PyObject *args) ++{ ++ struct type *type = ((type_object *) self)->type; ++ volatile struct gdb_exception except; ++ ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ type = make_cv_type (0, 1, type, NULL); ++ } ++ GDB_PY_HANDLE_EXCEPTION (except); ++ ++ return type_to_type_object (type); ++} ++ ++/* Return an unqualified type variant. */ ++static PyObject * ++typy_unqualified (PyObject *self, PyObject *args) ++{ ++ struct type *type = ((type_object *) self)->type; ++ volatile struct gdb_exception except; ++ ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ type = make_cv_type (0, 0, type, NULL); ++ } ++ GDB_PY_HANDLE_EXCEPTION (except); ++ ++ return type_to_type_object (type); ++} ++ ++/* Return the size of the type represented by SELF, in bytes. */ ++static PyObject * ++typy_sizeof (PyObject *self, PyObject *args) ++{ ++ struct type *type = ((type_object *) self)->type; ++ volatile struct gdb_exception except; ++ ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ CHECK_TYPEDEF (type); ++ } ++ GDB_PY_HANDLE_EXCEPTION (except); ++ ++ return PyLong_FromLong (TYPE_LENGTH (type)); ++} ++ ++static struct type * ++typy_lookup_typename (char *type_name, struct block *block) ++{ ++ struct type *type = NULL; ++ volatile struct gdb_exception except; ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ if (!strncmp (type_name, "struct ", 7)) ++ type = lookup_struct (type_name + 7, block); ++ else if (!strncmp (type_name, "union ", 6)) ++ type = lookup_union (type_name + 6, block); ++ else if (!strncmp (type_name, "enum ", 5)) ++ type = lookup_enum (type_name + 5, block); ++ else ++ type = lookup_typename (type_name, block, 0); ++ } ++ if (except.reason < 0) ++ { ++ PyErr_Format (except.reason == RETURN_QUIT ++ ? PyExc_KeyboardInterrupt : PyExc_RuntimeError, ++ "%s", except.message); ++ return NULL; ++ } ++ ++ return type; ++} ++ ++static struct type * ++typy_lookup_type (struct demangle_component *demangled, ++ struct block *block) ++{ ++ struct type *type; ++ char *type_name; ++ enum demangle_component_type demangled_type; ++ ++ /* Save the type: typy_lookup_type() may (indirectly) overwrite ++ memory pointed by demangled. */ ++ demangled_type = demangled->type; ++ ++ if (demangled_type == DEMANGLE_COMPONENT_POINTER ++ || demangled_type == DEMANGLE_COMPONENT_REFERENCE ++ || demangled_type == DEMANGLE_COMPONENT_CONST ++ || demangled_type == DEMANGLE_COMPONENT_VOLATILE) ++ { ++ type = typy_lookup_type (demangled->u.s_binary.left, block); ++ if (! type) ++ return NULL; ++ ++ switch (demangled_type) ++ { ++ case DEMANGLE_COMPONENT_REFERENCE: ++ return lookup_reference_type (type); ++ case DEMANGLE_COMPONENT_POINTER: ++ return lookup_pointer_type (type); ++ case DEMANGLE_COMPONENT_CONST: ++ return make_cv_type (1, 0, type, NULL); ++ case DEMANGLE_COMPONENT_VOLATILE: ++ return make_cv_type (0, 1, type, NULL); ++ } ++ } ++ ++ type_name = cp_comp_to_string (demangled, 10); ++ type = typy_lookup_typename (type_name, block); ++ xfree (type_name); ++ ++ return type; ++} ++ ++static PyObject * ++typy_template_argument (PyObject *self, PyObject *args) ++{ ++ int i, argno, n_pointers; ++ struct type *type = ((type_object *) self)->type; ++ struct demangle_component *demangled; ++ const char *err; ++ struct type *argtype; ++ struct block *block = NULL; ++ PyObject *block_obj = NULL; ++ ++ if (! PyArg_ParseTuple (args, "i|O", &argno, &block_obj)) ++ return NULL; ++ ++ if (block_obj) ++ { ++ block = block_object_to_block (block_obj); ++ if (! block) ++ { ++ PyErr_SetString (PyExc_RuntimeError, ++ "second argument must be block"); ++ return NULL; ++ } ++ } ++ ++ type = check_typedef (type); ++ if (TYPE_CODE (type) == TYPE_CODE_REF) ++ type = check_typedef (TYPE_TARGET_TYPE (type)); ++ ++ if (TYPE_NAME (type) == NULL) ++ { ++ PyErr_SetString (PyExc_RuntimeError, "null type name"); ++ return NULL; ++ } ++ ++ /* Note -- this is not thread-safe. */ ++ demangled = cp_demangled_name_to_comp (TYPE_NAME (type), &err); ++ if (! demangled) ++ { ++ PyErr_SetString (PyExc_RuntimeError, err); ++ return NULL; ++ } ++ ++ /* Strip off component names. */ ++ while (demangled->type == DEMANGLE_COMPONENT_QUAL_NAME ++ || demangled->type == DEMANGLE_COMPONENT_LOCAL_NAME) ++ demangled = demangled->u.s_binary.right; ++ ++ if (demangled->type != DEMANGLE_COMPONENT_TEMPLATE) ++ { ++ PyErr_SetString (PyExc_RuntimeError, "type is not a template"); ++ return NULL; ++ } ++ ++ /* Skip from the template to the arguments. */ ++ demangled = demangled->u.s_binary.right; ++ ++ for (i = 0; demangled && i < argno; ++i) ++ demangled = demangled->u.s_binary.right; ++ ++ if (! demangled) ++ { ++ PyErr_Format (PyExc_RuntimeError, "no argument %d in template", ++ argno); ++ return NULL; ++ } ++ ++ argtype = typy_lookup_type (demangled->u.s_binary.left, block); ++ if (! argtype) ++ return NULL; ++ ++ return type_to_type_object (argtype); ++} ++ ++static PyObject * ++typy_str (PyObject *self) ++{ ++ volatile struct gdb_exception except; ++ char *thetype = NULL; ++ PyObject *result; ++ ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ struct cleanup *old_chain; ++ struct ui_file *stb; ++ long length; ++ ++ stb = mem_fileopen (); ++ old_chain = make_cleanup_ui_file_delete (stb); ++ ++ type_print (type_object_to_type (self), "", stb, -1); ++ ++ thetype = ui_file_xstrdup (stb, &length); ++ do_cleanups (old_chain); ++ } ++ if (except.reason < 0) ++ { ++ xfree (thetype); ++ GDB_PY_HANDLE_EXCEPTION (except); ++ } ++ ++ result = PyUnicode_Decode (thetype, strlen (thetype), host_charset (), NULL); ++ xfree (thetype); ++ ++ return result; ++} ++ ++ ++ ++static const struct objfile_data *typy_objfile_data_key; ++ ++static void ++clean_up_objfile_types (struct objfile *objfile, void *datum) ++{ ++ type_object *obj = datum; ++ htab_t copied_types; ++ struct cleanup *cleanup; ++ PyGILState_STATE state; ++ ++ /* This prevents another thread from freeing the objects we're ++ operating on. */ ++ state = PyGILState_Ensure (); ++ cleanup = make_cleanup_py_restore_gil (&state); ++ ++ copied_types = create_copied_types_hash (objfile); ++ ++ while (obj) ++ { ++ type_object *next = obj->next; ++ ++ htab_empty (copied_types); ++ ++ /* No need to decref the old type here, since we know it has no ++ reference count. */ ++ gdb_assert (objfile == TYPE_OBJFILE (obj->type)); ++ obj->type = copy_type_recursive (obj->type, copied_types); ++ type_incref (obj->type); ++ ++ obj->next = NULL; ++ obj->prev = NULL; ++ ++ obj = next; ++ } ++ ++ htab_delete (copied_types); ++ ++ do_cleanups (cleanup); ++} ++ ++static void ++set_type (type_object *obj, struct type *type) ++{ ++ obj->type = type; ++ type_incref (type); ++ obj->prev = NULL; ++ if (type && !OBJFILE_IS_VIRTUAL (TYPE_OBJFILE (type))) ++ { ++ struct objfile *objfile = TYPE_OBJFILE (type); ++ ++ obj->next = objfile_data (objfile, typy_objfile_data_key); ++ if (obj->next) ++ obj->next->prev = obj; ++ set_objfile_data (objfile, typy_objfile_data_key, obj); ++ } ++ else ++ obj->next = NULL; ++} ++ ++static PyObject * ++typy_new (PyTypeObject *subtype, PyObject *args, PyObject *kwargs) ++{ ++ char *type_name = NULL; ++ struct type *type = NULL; ++ type_object *result; ++ PyObject *block_obj = NULL; ++ struct block *block = NULL; ++ ++ /* FIXME: it is strange to allow a Type with no name, but we need ++ this for type_to_type_object. */ ++ if (! PyArg_ParseTuple (args, "|sO", &type_name, &block_obj)) ++ return NULL; ++ ++ if (block_obj) ++ { ++ block = block_object_to_block (block_obj); ++ if (! block) ++ { ++ PyErr_SetString (PyExc_RuntimeError, ++ "second argument must be block"); ++ return NULL; ++ } ++ } ++ ++ if (type_name) ++ { ++ type = typy_lookup_typename (type_name, block); ++ if (! type) ++ return NULL; ++ } ++ ++ result = (type_object *) subtype->tp_alloc (subtype, 1); ++ if (! result) ++ return NULL; ++ ++ set_type (result, type); ++ ++ return (PyObject *) result; ++} ++ ++static void ++typy_dealloc (PyObject *obj) ++{ ++ type_object *type = (type_object *) obj; ++ ++ if (type->type) ++ type_decref (type->type); ++ ++ if (type->prev) ++ type->prev->next = type->next; ++ else if (type->type && !OBJFILE_IS_VIRTUAL (TYPE_OBJFILE (type->type))) ++ { ++ /* Must reset head of list. */ ++ struct objfile *objfile = TYPE_OBJFILE (type->type); ++ if (objfile) ++ set_objfile_data (objfile, typy_objfile_data_key, type->next); ++ } ++ if (type->next) ++ type->next->prev = type->prev; ++ ++ type->ob_type->tp_free (type); ++} ++ ++/* Create a new Type referring to TYPE. */ ++PyObject * ++type_to_type_object (struct type *type) ++{ ++ type_object *type_obj; ++ ++ type_obj = PyObject_New (type_object, &type_object_type); ++ if (type_obj) ++ set_type (type_obj, type); ++ ++ return (PyObject *) type_obj; ++} ++ ++struct type * ++type_object_to_type (PyObject *obj) ++{ ++ if (! PyObject_TypeCheck (obj, &type_object_type)) ++ return NULL; ++ return ((type_object *) obj)->type; ++} ++ ++ ++ ++void ++gdbpy_initialize_types (void) ++{ ++ int i; ++ ++ typy_objfile_data_key ++ = register_objfile_data_with_cleanup (clean_up_objfile_types); ++ ++ if (PyType_Ready (&type_object_type) < 0) ++ return; ++ if (PyType_Ready (&field_object_type) < 0) ++ return; ++ ++ for (i = 0; pyty_codes[i].name; ++i) ++ { ++ if (PyModule_AddIntConstant (gdb_module, ++ /* Cast needed for Python 2.4. */ ++ (char *) pyty_codes[i].name, ++ pyty_codes[i].code) < 0) ++ return; ++ } ++ ++ Py_INCREF (&type_object_type); ++ PyModule_AddObject (gdb_module, "Type", (PyObject *) &type_object_type); ++ ++ Py_INCREF (&field_object_type); ++ PyModule_AddObject (gdb_module, "Field", (PyObject *) &field_object_type); ++} ++ ++ ++ ++static PyMethodDef type_object_methods[] = ++{ ++ { "code", typy_code, METH_NOARGS, "Return the code for this type" }, ++ { "const", typy_const, METH_NOARGS, "Return a const variant of this type" }, ++ { "fields", typy_fields, METH_NOARGS, ++ "Return a sequence holding all the fields of this type.\n\ ++Each field is a dictionary." }, ++ { "pointer", typy_pointer, METH_NOARGS, "Return pointer to this type" }, ++ { "reference", typy_reference, METH_NOARGS, "Return reference to this type" }, ++ { "sizeof", typy_sizeof, METH_NOARGS, ++ "Return the size of this type, in bytes" }, ++ { "tag", typy_tag, METH_NOARGS, ++ "Return the tag name for this type, or None." }, ++ { "strip_typedefs", typy_strip_typedefs, METH_NOARGS, ++ "Return a type stripped of typedefs"}, ++ { "target", typy_target, METH_NOARGS, ++ "Return the target type of this type" }, ++ { "template_argument", typy_template_argument, METH_VARARGS, ++ "Return a single template argument type" }, ++ { "unqualified", typy_unqualified, METH_NOARGS, ++ "Return a variant of this type without const or volatile attributes" }, ++ { "volatile", typy_volatile, METH_NOARGS, ++ "Return a volatile variant of this type" }, ++ { NULL } ++}; ++ ++static PyTypeObject type_object_type = ++{ ++ PyObject_HEAD_INIT (NULL) ++ 0, /*ob_size*/ ++ "gdb.Type", /*tp_name*/ ++ sizeof (type_object), /*tp_basicsize*/ ++ 0, /*tp_itemsize*/ ++ typy_dealloc, /*tp_dealloc*/ ++ 0, /*tp_print*/ ++ 0, /*tp_getattr*/ ++ 0, /*tp_setattr*/ ++ 0, /*tp_compare*/ ++ 0, /*tp_repr*/ ++ 0, /*tp_as_number*/ ++ 0, /*tp_as_sequence*/ ++ 0, /*tp_as_mapping*/ ++ 0, /*tp_hash */ ++ 0, /*tp_call*/ ++ typy_str, /*tp_str*/ ++ 0, /*tp_getattro*/ ++ 0, /*tp_setattro*/ ++ 0, /*tp_as_buffer*/ ++ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER, /*tp_flags*/ ++ "GDB type object", /* tp_doc */ ++ 0, /* tp_traverse */ ++ 0, /* tp_clear */ ++ 0, /* tp_richcompare */ ++ 0, /* tp_weaklistoffset */ ++ 0, /* tp_iter */ ++ 0, /* tp_iternext */ ++ type_object_methods, /* tp_methods */ ++ 0, /* tp_members */ ++ 0, /* tp_getset */ ++ 0, /* tp_base */ ++ 0, /* tp_dict */ ++ 0, /* tp_descr_get */ ++ 0, /* tp_descr_set */ ++ 0, /* tp_dictoffset */ ++ 0, /* tp_init */ ++ 0, /* tp_alloc */ ++ typy_new, /* tp_new */ ++}; ++ ++static PyTypeObject field_object_type = ++{ ++ PyObject_HEAD_INIT (NULL) ++ 0, /*ob_size*/ ++ "gdb.Field", /*tp_name*/ ++ sizeof (field_object), /*tp_basicsize*/ ++ 0, /*tp_itemsize*/ ++ field_dealloc, /*tp_dealloc*/ ++ 0, /*tp_print*/ ++ 0, /*tp_getattr*/ ++ 0, /*tp_setattr*/ ++ 0, /*tp_compare*/ ++ 0, /*tp_repr*/ ++ 0, /*tp_as_number*/ ++ 0, /*tp_as_sequence*/ ++ 0, /*tp_as_mapping*/ ++ 0, /*tp_hash */ ++ 0, /*tp_call*/ ++ 0, /*tp_str*/ ++ 0, /*tp_getattro*/ ++ 0, /*tp_setattro*/ ++ 0, /*tp_as_buffer*/ ++ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER, /*tp_flags*/ ++ "GDB field object", /* tp_doc */ ++ 0, /* tp_traverse */ ++ 0, /* tp_clear */ ++ 0, /* tp_richcompare */ ++ 0, /* tp_weaklistoffset */ ++ 0, /* tp_iter */ ++ 0, /* tp_iternext */ ++ 0, /* tp_methods */ ++ 0, /* tp_members */ ++ 0, /* tp_getset */ ++ 0, /* tp_base */ ++ 0, /* tp_dict */ ++ 0, /* tp_descr_get */ ++ 0, /* tp_descr_set */ ++ offsetof (field_object, dict), /* tp_dictoffset */ ++ 0, /* tp_init */ ++ 0, /* tp_alloc */ ++ 0, /* tp_new */ ++}; +diff --git a/gdb/python/python-utils.c b/gdb/python/python-utils.c +index ddac2f5..f9c9486 100644 +--- a/gdb/python/python-utils.c ++++ b/gdb/python/python-utils.c +@@ -19,6 +19,7 @@ + + #include "defs.h" + #include "charset.h" ++#include "value.h" + #include "python-internal.h" + + +@@ -99,8 +100,8 @@ python_string_to_unicode (PyObject *obj) + } + + /* Returns a newly allocated string with the contents of the given unicode +- string object converted to CHARSET. If an error occurs during the +- conversion, NULL will be returned and a python exception will be set. ++ string object converted to a named charset. If an error occurs during ++ the conversion, NULL will be returned and a python exception will be set. + + The caller is responsible for xfree'ing the string. */ + static char * +@@ -191,3 +192,48 @@ gdbpy_is_string (PyObject *obj) + { + return PyString_Check (obj) || PyUnicode_Check (obj); + } ++ ++/* Converts OBJ to a CORE_ADDR value. ++ ++ Returns 1 on success or 0 on failure, with a Python exception set. This ++ function can also throw GDB exceptions. */ ++ ++int ++get_addr_from_python (PyObject *obj, CORE_ADDR *addr) ++{ ++ if (gdbpy_is_value_object (obj)) ++ *addr = value_as_address (value_object_to_value (obj)); ++ else if (PyLong_Check (obj)) ++ { ++ /* Assume CORE_ADDR corresponds to unsigned long. */ ++ *addr = PyLong_AsUnsignedLong (obj); ++ if (PyErr_Occurred () != NULL) ++ return 0; ++ } ++ else if (PyInt_Check (obj)) ++ { ++ long val; ++ ++ /* Assume CORE_ADDR corresponds to unsigned long. */ ++ val = PyInt_AsLong (obj); ++ ++ if (val >= 0) ++ *addr = val; ++ else ++ { ++ /* If no error ocurred, VAL is indeed negative. */ ++ if (PyErr_Occurred () != NULL) ++ return 0; ++ ++ PyErr_SetString (PyExc_ValueError, "negative address"); ++ return 0; ++ } ++ } ++ else ++ { ++ PyErr_SetString (PyExc_TypeError, "invalid type for address"); ++ return 0; ++ } ++ ++ return 1; ++} +diff --git a/gdb/python/python-value.c b/gdb/python/python-value.c +index bc077b6..2507fcd 100644 +--- a/gdb/python/python-value.c ++++ b/gdb/python/python-value.c +@@ -52,6 +52,10 @@ struct value *values_in_python = NULL; + /* Python's long type corresponds to C's long long type. */ + #define builtin_type_pylong builtin_type (current_gdbarch)->builtin_long_long + ++/* Python's long type corresponds to C's long long type. Unsigned version. */ ++#define builtin_type_upylong builtin_type \ ++ (current_gdbarch)->builtin_unsigned_long_long ++ + #define builtin_type_pybool \ + language_bool_type (current_language, current_gdbarch) + +@@ -143,10 +147,19 @@ valpy_address (PyObject *self, PyObject *args) + return value_to_value_object (res_val); + } + +-/* Return Unicode string with value contents (assumed to be encoded in the +- target's charset). */ ++/* Return type of the value. */ ++static PyObject * ++valpy_type (PyObject *self, PyObject *args) ++{ ++ struct value *value = ((value_object *) self)->value; ++ return type_to_type_object (value_type (value)); ++} ++ ++/* Implementation of gdb.Value.string ([encoding] [, errors]) -> string ++ Return Unicode string with value contents. If ENCODING is not given, ++ the string is assumed to be encoded in the target's charset. */ + static PyObject * +-valpy_string (PyObject *self, PyObject *args) ++valpy_string (PyObject *self, PyObject *args, PyObject *kw) + { + int length, ret = 0; + gdb_byte *buffer; +@@ -157,8 +170,10 @@ valpy_string (PyObject *self, PyObject *args) + const char *errors = NULL; + const char *user_encoding = NULL; + const char *la_encoding = NULL; ++ static char *keywords[] = { "encoding", "errors" }; + +- if (!PyArg_ParseTuple (args, "|ss", &user_encoding, &errors)) ++ if (!PyArg_ParseTupleAndKeywords (args, kw, "|ss", keywords, ++ &user_encoding, &errors)) + return NULL; + + TRY_CATCH (except, RETURN_MASK_ALL) +@@ -174,6 +189,34 @@ valpy_string (PyObject *self, PyObject *args) + return unicode; + } + ++/* Cast a value to a given type. */ ++static PyObject * ++valpy_cast (PyObject *self, PyObject *args) ++{ ++ PyObject *type_obj; ++ struct type *type; ++ struct value *res_val = NULL; /* Initialize to appease gcc warning. */ ++ volatile struct gdb_exception except; ++ ++ if (! PyArg_ParseTuple (args, "O", &type_obj)) ++ return NULL; ++ ++ type = type_object_to_type (type_obj); ++ if (! type) ++ { ++ PyErr_SetString (PyExc_RuntimeError, "argument must be a Type"); ++ return NULL; ++ } ++ ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ res_val = value_cast (type, ((value_object *) self)->value); ++ } ++ GDB_PY_HANDLE_EXCEPTION (except); ++ ++ return value_to_value_object (res_val); ++} ++ + static Py_ssize_t + valpy_length (PyObject *self) + { +@@ -306,11 +349,11 @@ valpy_binop (enum valpy_opcode opcode, PyObject *self, PyObject *other) + a gdb.Value object and need to convert it from python as well. */ + arg1 = convert_value_from_python (self); + if (arg1 == NULL) +- return NULL; ++ break; + + arg2 = convert_value_from_python (other); + if (arg2 == NULL) +- return NULL; ++ break; + + switch (opcode) + { +@@ -387,7 +430,7 @@ valpy_binop (enum valpy_opcode opcode, PyObject *self, PyObject *other) + } + GDB_PY_HANDLE_EXCEPTION (except); + +- return value_to_value_object (res_val); ++ return res_val ? value_to_value_object (res_val) : NULL; + } + + static PyObject * +@@ -718,6 +761,17 @@ value_to_value_object (struct value *val) + return (PyObject *) val_obj; + } + ++/* Returns value structure corresponding to the given value object. */ ++struct value * ++value_object_to_value (PyObject *self) ++{ ++ value_object *real; ++ if (! PyObject_TypeCheck (self, &value_object_type)) ++ return NULL; ++ real = (value_object *) self; ++ return real->value; ++} ++ + /* Try to convert a Python value to a gdb value. If the value cannot + be converted, set a Python exception and return NULL. */ + +@@ -751,7 +805,34 @@ convert_value_from_python (PyObject *obj) + { + LONGEST l = PyLong_AsLongLong (obj); + +- if (! PyErr_Occurred ()) ++ if (PyErr_Occurred ()) ++ { ++ /* If the error was an overflow, we can try converting to ++ ULONGEST instead. */ ++ if (PyErr_ExceptionMatches (PyExc_OverflowError)) ++ { ++ PyObject *etype, *evalue, *etraceback, *zero; ++ ++ PyErr_Fetch (&etype, &evalue, &etraceback); ++ zero = PyInt_FromLong (0); ++ ++ /* Check whether obj is positive. */ ++ if (PyObject_RichCompareBool (obj, zero, Py_GT) > 0) ++ { ++ ULONGEST ul; ++ ++ ul = PyLong_AsUnsignedLongLong (obj); ++ if (! PyErr_Occurred ()) ++ value = value_from_ulongest (builtin_type_upylong, ul); ++ } ++ else ++ /* There's nothing we can do. */ ++ PyErr_Restore (etype, evalue, etraceback); ++ ++ Py_DECREF (zero); ++ } ++ } ++ else + value = value_from_longest (builtin_type_pylong, l); + } + else if (PyFloat_Check (obj)) +@@ -774,7 +855,7 @@ convert_value_from_python (PyObject *obj) + } + } + else if (PyObject_TypeCheck (obj, &value_object_type)) +- value = ((value_object *) obj)->value; ++ value = value_copy (((value_object *) obj)->value); + else + PyErr_Format (PyExc_TypeError, _("Could not convert Python object: %s"), + PyString_AsString (PyObject_Str (obj))); +@@ -810,6 +891,14 @@ gdbpy_history (PyObject *self, PyObject *args) + return value_to_value_object (res_val); + } + ++/* Returns 1 in OBJ is a gdb.Value object, 0 otherwise. */ ++ ++int ++gdbpy_is_value_object (PyObject *obj) ++{ ++ return PyObject_TypeCheck (obj, &value_object_type); ++} ++ + void + gdbpy_initialize_values (void) + { +@@ -822,11 +911,16 @@ gdbpy_initialize_values (void) + values_in_python = NULL; + } + ++ ++ + static PyMethodDef value_object_methods[] = { + { "address", valpy_address, METH_NOARGS, "Return the address of the value." }, ++ { "cast", valpy_cast, METH_VARARGS, "Cast the value to the supplied type." }, + { "dereference", valpy_dereference, METH_NOARGS, "Dereferences the value." }, +- { "string", valpy_string, METH_VARARGS, +- "Return Unicode string representation of the value." }, ++ { "type", valpy_type, METH_NOARGS, "Return type of the value." }, ++ { "string", (PyCFunction) valpy_string, METH_VARARGS | METH_KEYWORDS, ++ "string ([encoding] [, errors]) -> string\n\ ++Return Unicode string representation of the value." }, + {NULL} /* Sentinel */ + }; + +diff --git a/gdb/python/python.c b/gdb/python/python.c +index b3a27d6..2b06748 100644 +--- a/gdb/python/python.c ++++ b/gdb/python/python.c +@@ -22,6 +22,12 @@ + #include "ui-out.h" + #include "cli/cli-script.h" + #include "gdbcmd.h" ++#include "objfiles.h" ++#include "observer.h" ++#include "gdb_regex.h" ++#include "language.h" ++#include "valprint.h" ++#include "event-loop.h" + + #include + +@@ -29,6 +35,10 @@ + false otherwise. */ + static int gdbpy_should_print_stack = 1; + ++/* This is true if we should auto-load python code when an objfile is ++ opened, false otherwise. */ ++static int gdbpy_auto_load = 1; ++ + #ifdef HAVE_PYTHON + + #include "python.h" +@@ -36,16 +46,29 @@ static int gdbpy_should_print_stack = 1; + #include "cli/cli-decode.h" + #include "charset.h" + #include "top.h" ++#include "solib.h" + #include "exceptions.h" + #include "python-internal.h" ++#include "linespec.h" ++#include "symtab.h" ++#include "source.h" + #include "version.h" ++#include "inferior.h" ++#include "gdbthread.h" + #include "target.h" + #include "gdbthread.h" ++#include "event-top.h" ++ ++static PyMethodDef GdbMethods[]; + + static PyMethodDef GdbMethods[]; + + PyObject *gdb_module; + ++/* Some string constants we may wish to use. */ ++PyObject *gdbpy_to_string_cst; ++PyObject *gdbpy_children_cst; ++PyObject *gdbpy_display_hint_cst; + PyObject *gdbpy_doc_cst; + + /* Given a command_line, return a command string suitable for passing +@@ -143,10 +166,10 @@ python_command (char *arg, int from_tty) + NULL (and set a Python exception) on error. Helper function for + get_parameter. */ + +-static PyObject * +-parameter_to_python (struct cmd_list_element *cmd) ++PyObject * ++gdbpy_parameter_value (enum var_types type, void *var) + { +- switch (cmd->var_type) ++ switch (type) + { + case var_string: + case var_string_noescape: +@@ -154,7 +177,7 @@ parameter_to_python (struct cmd_list_element *cmd) + case var_filename: + case var_enum: + { +- char *str = * (char **) cmd->var; ++ char *str = * (char **) var; + if (! str) + str = ""; + return PyString_Decode (str, strlen (str), host_charset (), NULL); +@@ -162,7 +185,7 @@ parameter_to_python (struct cmd_list_element *cmd) + + case var_boolean: + { +- if (* (int *) cmd->var) ++ if (* (int *) var) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +@@ -170,7 +193,7 @@ parameter_to_python (struct cmd_list_element *cmd) + + case var_auto_boolean: + { +- enum auto_boolean ab = * (enum auto_boolean *) cmd->var; ++ enum auto_boolean ab = * (enum auto_boolean *) var; + if (ab == AUTO_BOOLEAN_TRUE) + Py_RETURN_TRUE; + else if (ab == AUTO_BOOLEAN_FALSE) +@@ -180,15 +203,15 @@ parameter_to_python (struct cmd_list_element *cmd) + } + + case var_integer: +- if ((* (int *) cmd->var) == INT_MAX) ++ if ((* (int *) var) == INT_MAX) + Py_RETURN_NONE; + /* Fall through. */ + case var_zinteger: +- return PyLong_FromLong (* (int *) cmd->var); ++ return PyLong_FromLong (* (int *) var); + + case var_uinteger: + { +- unsigned int val = * (unsigned int *) cmd->var; ++ unsigned int val = * (unsigned int *) var; + if (val == UINT_MAX) + Py_RETURN_NONE; + return PyLong_FromUnsignedLong (val); +@@ -202,10 +225,11 @@ parameter_to_python (struct cmd_list_element *cmd) + value. */ + + static PyObject * +-get_parameter (PyObject *self, PyObject *args) ++gdbpy_parameter (PyObject *self, PyObject *args) + { + struct cmd_list_element *alias, *prefix, *cmd; + char *arg, *newarg; ++ int found = -1; + volatile struct gdb_exception except; + + if (! PyArg_ParseTuple (args, "s", &arg)) +@@ -215,19 +239,17 @@ get_parameter (PyObject *self, PyObject *args) + + TRY_CATCH (except, RETURN_MASK_ALL) + { +- if (! lookup_cmd_composition (newarg, &alias, &prefix, &cmd)) +- { +- xfree (newarg); +- return PyErr_Format (PyExc_RuntimeError, +- "could not find variable `%s'", arg); +- } ++ found = lookup_cmd_composition (newarg, &alias, &prefix, &cmd); + } + xfree (newarg); + GDB_PY_HANDLE_EXCEPTION (except); ++ if (!found) ++ return PyErr_Format (PyExc_RuntimeError, ++ "could not find parameter `%s'", arg); + + if (! cmd->var) +- return PyErr_Format (PyExc_RuntimeError, "`%s' is not a variable", arg); +- return parameter_to_python (cmd); ++ return PyErr_Format (PyExc_RuntimeError, "`%s' is not a parameter", arg); ++ return gdbpy_parameter_value (cmd->var_type, cmd->var); + } + + /* A Python function which evaluates a string using the gdb CLI. */ +@@ -266,6 +288,570 @@ execute_gdb_command (PyObject *self, PyObject *args) + Py_RETURN_NONE; + } + ++/* Implementation of gdb.solib_address (Long) -> String. ++ Returns the name of the shared library holding a given address, or None. */ ++ ++static PyObject * ++gdbpy_solib_address (PyObject *self, PyObject *args) ++{ ++ unsigned long long pc; ++ char *soname; ++ PyObject *str_obj; ++ ++ if (!PyArg_ParseTuple (args, "K", &pc)) ++ return NULL; ++ ++ soname = solib_address (pc); ++ if (soname) ++ str_obj = PyString_Decode (soname, strlen (soname), host_charset (), NULL); ++ else ++ { ++ str_obj = Py_None; ++ Py_INCREF (Py_None); ++ } ++ ++ return str_obj; ++} ++ ++static PyObject * ++gdbpy_find_pc_function (PyObject *self, PyObject *args) ++{ ++ unsigned long long pc; ++ struct symbol *sym; ++ PyObject *sym_obj; ++ ++ if (!PyArg_ParseTuple (args, "K", &pc)) ++ return NULL; ++ ++ sym = find_pc_function (pc); ++ if (sym) ++ return symbol_to_symbol_object (sym); ++ ++ Py_RETURN_NONE; ++} ++ ++/* Adds GDB value V to the pattern buffer in *PATTERN_BUF. If SIZE is not zero, ++ it specifies the number of bytes from V to copy to *PATTERN_BUF. The ++ function increases the size of *PATTERN_BUF as necessary, adjusting ++ *PATTERN_BUF_END and *PATTERN_BUF_SIZE in the process. */ ++ ++static void ++add_value_pattern (struct value *v, int size, char **pattern_buf, ++ char **pattern_buf_end, ULONGEST *pattern_buf_size) ++{ ++ int val_bytes; ++ ++ if (size) ++ { ++ LONGEST x = value_as_long (v); ++ ++ if (size == 1) ++ *(*pattern_buf_end)++ = x; ++ else ++ { ++ put_bits (x, *pattern_buf_end, size * 8, ++ gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG); ++ *pattern_buf_end += size; ++ } ++ } ++ else ++ { ++ val_bytes = TYPE_LENGTH (value_type (v)); ++ ++ increase_pattern_buffer (pattern_buf, pattern_buf_end, ++ pattern_buf_size, val_bytes); ++ ++ memcpy (*pattern_buf_end, value_contents_raw (v), val_bytes); ++ *pattern_buf_end += val_bytes; ++ } ++} ++ ++/* This function does the actual work of constructing the pattern buffer from ++ OBJ. If OBJ is an object which implements the read buffer protocol (such ++ as a string, a byte array or gdb.Membuf), then its contents are directly ++ copied to *PATTERN_BUF. If it is a list, then this function is recursively ++ called for each of its elements. If OBJ is an object which can be converted ++ to a GDB value, then the contents of the value are copied to PATTERN_BUF. ++ If SIZE is different than zero, then it limits the number of bytes which ++ are copied to the buffer in case OBJ is converted to a GDB value. That ++ means that SIZE influences only Python scalars and gdb.Value objects. ++ The function increases the size of *PATTERN_BUF as necessary, adjusting ++ *PATTERN_BUF_END and *PATTERN_BUF_SIZE in the process. ++ ++ Returns 1 on success or 0 on failure, with a Python exception set. This ++ function can also throw GDB exceptions. */ ++ ++static int ++add_pattern_element (PyObject *obj, int size, char **pattern_buf, ++ char **pattern_buf_end, ULONGEST *pattern_buf_size) ++{ ++ if (PyObject_CheckReadBuffer (obj)) ++ { ++ /* Handle string, Unicode string, byte array, gdb.Membuf and any other ++ object implementing the buffer protocol. The SIZE parameter is ++ ignored in this case. */ ++ ++ Py_ssize_t val_bytes; ++ const void *buffer; ++ ++ if (PyObject_AsReadBuffer (obj, &buffer, &val_bytes) == -1) ++ return 0; ++ ++ increase_pattern_buffer (pattern_buf, pattern_buf_end, ++ pattern_buf_size, val_bytes); ++ ++ memcpy (*pattern_buf_end, buffer, val_bytes); ++ *pattern_buf_end += val_bytes; ++ } ++ else if (gdbpy_is_value_object (obj)) ++ add_value_pattern (value_object_to_value (obj), size, pattern_buf, ++ pattern_buf_end, pattern_buf_size); ++ else if (PySequence_Check (obj)) ++ { ++ /* Handle lists and tuples. */ ++ ++ Py_ssize_t i, num_objs; ++ ++ num_objs = PySequence_Size (obj); ++ for (i = 0; i < num_objs; i++) ++ if (!add_pattern_element (PySequence_GetItem (obj, i), size, ++ pattern_buf, pattern_buf_end, ++ pattern_buf_size)) ++ return 0; ++ } ++ else ++ { ++ /* See if we can convert from a Python object to a GDB value. */ ++ ++ struct value *v = convert_value_from_python (obj); ++ ++ if (v) ++ add_value_pattern (v, size, pattern_buf, pattern_buf_end, ++ pattern_buf_size); ++ else ++ return 0; ++ } ++ ++ return 1; ++} ++ ++/* Constructs the search pattern from OBJ, putting it in *PATTERN_BUFP, and its ++ size in *PATTERN_LENP. See the function add_pattern_element to learn how ++ the search pattern is obtained from OBJ. ++ ++ Returns 1 on success or 0 on failure, with a Python exception set. This ++ function can also throw GDB exceptions. */ ++ ++static int ++get_search_pattern (PyObject *obj, int size, char **pattern_bufp, ++ ULONGEST *pattern_lenp) ++{ ++ /* Buffer to hold the search pattern. */ ++ char *pattern_buf; ++ /* Current size of search pattern buffer. ++ We realloc space as needed. */ ++ ULONGEST pattern_buf_size; ++ /* Pointer to one past the last in-use part of pattern_buf. */ ++ char *pattern_buf_end; ++ struct cleanup *old_cleanups; ++ ++ allocate_pattern_buffer (&pattern_buf, &pattern_buf_end, &pattern_buf_size); ++ old_cleanups = make_cleanup (free_current_contents, &pattern_buf); ++ ++ if (!add_pattern_element (obj, size, &pattern_buf, &pattern_buf_end, ++ &pattern_buf_size)) ++ { ++ do_cleanups (old_cleanups); ++ ++ return 0; ++ } ++ ++ *pattern_bufp = pattern_buf; ++ *pattern_lenp = pattern_buf_end - pattern_buf; ++ ++ discard_cleanups (old_cleanups); ++ ++ return 1; ++} ++ ++/* Implementation of ++ gdb.search_memory (address, length, pattern [, size] [, max_count]). ++ The third argument may be either a pattern, or a list or tupple of patterns ++ to be searched. Size is the size in bytes of each search query value, either ++ 1, 2, 4 or 8. Returns a list of the addresses where matches were found. */ ++ ++PyObject * ++gdbpy_search_memory (PyObject *self, PyObject *args, PyObject *kw) ++{ ++ int size = 0; ++ long length; ++ unsigned int found_count = 0; ++ long max_count = 0; ++ CORE_ADDR start_addr; ++ char *pattern_buf; ++ static char *keywords[] = { "address", "length", "pattern", "size", ++ "max_count", NULL }; ++ ULONGEST pattern_len, search_space_len; ++ PyObject *pattern, *list = NULL, *start_addr_obj; ++ volatile struct gdb_exception except; ++ ++ /* Assume CORE_ADDR corresponds to unsigned long. */ ++ if (! PyArg_ParseTupleAndKeywords (args, kw, "OlO|il", keywords, ++ &start_addr_obj, &length, &pattern, ++ &size, &max_count)) ++ return NULL; ++ ++ if (!max_count) ++ max_count = LONG_MAX; ++ ++ if (!length) ++ { ++ PyErr_SetString (PyExc_ValueError, "empty search range"); ++ return NULL; ++ } ++ else if (length < 0) ++ { ++ PyErr_SetString (PyExc_ValueError, "invalid search range"); ++ return NULL; ++ } ++ else ++ { ++ /* Watch for overflows. */ ++ if (length > CORE_ADDR_MAX ++ || (start_addr + length - 1) < start_addr) ++ { ++ PyErr_SetString (PyExc_ValueError, "search range too large"); ++ return NULL; ++ } ++ ++ search_space_len = length; ++ } ++ ++ if (size != 0 && size != 1 && size != 2 && size != 4 && size != 8) ++ { ++ PyErr_SetString (PyExc_ValueError, "invalid pattern size"); ++ return NULL; ++ } ++ ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ if (get_addr_from_python (start_addr_obj, &start_addr)) ++ { ++ if (get_search_pattern (pattern, size, &pattern_buf, &pattern_len)) ++ { ++ /* Any cleanups get automatically executed on an exception. */ ++ struct cleanup *cleanups = make_cleanup (xfree, pattern_buf); ++ ++ list = PyList_New (0); ++ ++ while (search_space_len >= pattern_len && found_count < max_count) ++ { ++ CORE_ADDR found_addr; ++ int found; ++ ++ found = search_memory (&start_addr, &search_space_len, ++ pattern_buf, pattern_len, &found_addr); ++ if (found <= 0) ++ break; ++ ++ PyList_Append (list, PyLong_FromUnsignedLong (found_addr)); ++ ++found_count; ++ } ++ ++ do_cleanups (cleanups); ++ } ++ } ++ } ++ GDB_PY_HANDLE_EXCEPTION (except); ++ ++ return list; ++} ++ ++/* A Python function which is a wrapper for decode_line_1. */ ++ ++static PyObject * ++gdbpy_decode_line (PyObject *self, PyObject *args) ++{ ++ struct symtabs_and_lines sals = { NULL, 0 }; /* Initialize to appease gcc. */ ++ struct symtab_and_line sal; ++ char *arg = NULL; ++ int free_sals = 0, i; ++ PyObject *result = NULL; ++ volatile struct gdb_exception except; ++ ++ if (! PyArg_ParseTuple (args, "|s", &arg)) ++ return NULL; ++ ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ if (arg) ++ { ++ char *copy; ++ ++ arg = strdup (arg); ++ copy = arg; ++ ++ sals = decode_line_1 (©, 0, 0, 0, 0, 0); ++ free_sals = 1; ++ } ++ else ++ { ++ set_default_source_symtab_and_line (); ++ sal = get_current_source_symtab_and_line (); ++ sals.sals = &sal; ++ sals.nelts = 1; ++ } ++ } ++ if (arg) ++ xfree (arg); ++ ++ if (except.reason < 0) ++ { ++ if (free_sals) ++ xfree (sals.sals); ++ /* We know this will always throw. */ ++ GDB_PY_HANDLE_EXCEPTION (except); ++ } ++ ++ if (sals.nelts) ++ { ++ result = PyTuple_New (sals.nelts); ++ for (i = 0; i < sals.nelts; ++i) ++ { ++ PyObject *obj; ++ char *str; ++ ++ obj = symtab_and_line_to_sal_object (sals.sals[i]); ++ if (! obj) ++ { ++ Py_DECREF (result); ++ result = NULL; ++ break; ++ } ++ ++ PyTuple_SetItem (result, i, obj); ++ } ++ } ++ ++ if (free_sals) ++ xfree (sals.sals); ++ ++ if (result) ++ return result; ++ Py_RETURN_NONE; ++} ++ ++/* Parse a string and evaluate it as an expression. */ ++static PyObject * ++gdbpy_parse_and_eval (PyObject *self, PyObject *args) ++{ ++ char *expr_str; ++ struct value *result = NULL; ++ volatile struct gdb_exception except; ++ ++ if (!PyArg_ParseTuple (args, "s", &expr_str)) ++ return NULL; ++ ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ result = parse_and_eval (expr_str); ++ } ++ GDB_PY_HANDLE_EXCEPTION (except); ++ ++ return value_to_value_object (result); ++} ++ ++ ++ ++/* Posting and handling events. */ ++ ++/* A single event. */ ++struct gdbpy_event ++{ ++ /* The Python event. This is just a callable object. */ ++ PyObject *event; ++ /* The next event. */ ++ struct gdbpy_event *next; ++}; ++ ++/* All pending events. */ ++static struct gdbpy_event *gdbpy_event_list; ++/* The final link of the event list. */ ++static struct gdbpy_event **gdbpy_event_list_end; ++ ++/* We use a file handler, and not an async handler, so that we can ++ wake up the main thread even when it is blocked in poll(). */ ++static int gdbpy_event_fds[2]; ++ ++/* The file handler callback. This reads from the internal pipe, and ++ then processes the Python event queue. This will always be run in ++ the main gdb thread. */ ++static void ++gdbpy_run_events (int err, gdb_client_data ignore) ++{ ++ PyGILState_STATE state; ++ char buffer[100]; ++ int r; ++ ++ state = PyGILState_Ensure (); ++ ++ /* Just read whatever is available on the fd. It is relatively ++ harmless if there are any bytes left over. */ ++ r = read (gdbpy_event_fds[0], buffer, sizeof (buffer)); ++ ++ while (gdbpy_event_list) ++ { ++ /* Dispatching the event might push a new element onto the event ++ loop, so we update here "atomically enough". */ ++ struct gdbpy_event *item = gdbpy_event_list; ++ gdbpy_event_list = gdbpy_event_list->next; ++ if (gdbpy_event_list == NULL) ++ gdbpy_event_list_end = &gdbpy_event_list; ++ ++ /* Ignore errors. */ ++ PyObject_CallObject (item->event, NULL); ++ ++ Py_DECREF (item->event); ++ xfree (item); ++ } ++ ++ PyGILState_Release (state); ++} ++ ++/* Submit an event to the gdb thread. */ ++static PyObject * ++gdbpy_post_event (PyObject *self, PyObject *args) ++{ ++ struct gdbpy_event *event; ++ PyObject *func; ++ int wakeup; ++ ++ if (!PyArg_ParseTuple (args, "O", &func)) ++ return NULL; ++ ++ if (!PyCallable_Check (func)) ++ { ++ PyErr_SetString (PyExc_RuntimeError, "Posted event is not callable"); ++ return NULL; ++ } ++ ++ Py_INCREF (func); ++ ++ /* From here until the end of the function, we have the GIL, so we ++ can operate on our global data structures without worrying. */ ++ wakeup = gdbpy_event_list == NULL; ++ ++ event = XNEW (struct gdbpy_event); ++ event->event = func; ++ event->next = NULL; ++ *gdbpy_event_list_end = event; ++ gdbpy_event_list_end = &event->next; ++ ++ /* Wake up gdb when needed. */ ++ if (wakeup) ++ { ++ char c = 'q'; /* Anything. */ ++ if (write (gdbpy_event_fds[1], &c, 1) != 1) ++ return PyErr_SetFromErrno (PyExc_IOError); ++ } ++ ++ Py_RETURN_NONE; ++} ++ ++/* Initialize the Python event handler. */ ++static void ++gdbpy_initialize_events (void) ++{ ++ if (!pipe (gdbpy_event_fds)) ++ { ++ gdbpy_event_list_end = &gdbpy_event_list; ++ add_file_handler (gdbpy_event_fds[0], gdbpy_run_events, NULL); ++ } ++} ++ ++ ++ ++/* Threads. */ ++ ++/* Callback function for use with iterate_over_threads. This function ++ just counts the number of threads. */ ++ ++static int ++count_callback (struct thread_info *info, void *user_data) ++{ ++ int *count = (int *) user_data; ++ ++*count; ++ return 0; ++} ++ ++/* Structure for storing some state when iterating over threads. */ ++ ++struct set_thread_info ++{ ++ PyObject *tuple; ++ int index; ++}; ++ ++/* Callback function for use with iterate_over_threads. This function ++ stores the thread ID into a Python tuple. */ ++ ++static int ++update_tuple_callback (struct thread_info *info, void *user_data) ++{ ++ struct set_thread_info *tinfo = (struct set_thread_info *) user_data; ++ PyTuple_SetItem (tinfo->tuple, tinfo->index, PyInt_FromLong (info->num)); ++ ++tinfo->index; ++ return 0; ++} ++ ++/* Python function which yields a tuple holding all valid thread IDs. */ ++ ++static PyObject * ++gdbpy_threads (PyObject *unused1, PyObject *unused2) ++{ ++ int thread_count = 0; ++ struct set_thread_info info; ++ PyObject *result; ++ ++ prune_threads (); ++ target_find_new_threads (); ++ ++ iterate_over_threads (count_callback, &thread_count); ++ ++ if (!thread_count) ++ Py_RETURN_NONE; ++ ++ result = PyTuple_New (thread_count); ++ info.tuple = result; ++ info.index = 0; ++ iterate_over_threads (update_tuple_callback, &info); ++ return result; ++} ++ ++/* Python function that returns the current thread's ID. */ ++ ++static PyObject * ++gdbpy_current_thread (PyObject *unused1, PyObject *unused2) ++{ ++ if (PIDGET (inferior_ptid) == 0) ++ Py_RETURN_NONE; ++ return PyInt_FromLong (pid_to_thread_id (inferior_ptid)); ++} ++ ++/* Python function for switching to a given thread. */ ++ ++static PyObject * ++gdbpy_switch_to_thread (PyObject *self, PyObject *args) ++{ ++ int id; ++ if (! PyArg_ParseTuple (args, "i", &id)) ++ return NULL; ++ if (! valid_thread_id (id)) ++ return PyErr_Format (PyExc_RuntimeError, "invalid thread id"); ++ switch_to_thread (thread_id_to_pid (id)); ++ Py_RETURN_NONE; ++} ++ + + + /* Printing. */ +@@ -302,6 +888,769 @@ gdbpy_print_stack (void) + PyErr_Clear (); + } + ++ ++ ++/* Script interface. */ ++ ++/* True if 'gdb -P' was used, false otherwise. */ ++static int running_python_script; ++ ++/* True if we are currently in a call to 'gdb.cli', false otherwise. */ ++static int in_cli; ++ ++/* Enter the command loop. */ ++ ++static PyObject * ++gdbpy_cli (PyObject *unused1, PyObject *unused2) ++{ ++ if (! running_python_script || in_cli) ++ return PyErr_Format (PyExc_RuntimeError, "cannot invoke CLI recursively"); ++ ++ in_cli = 1; ++ cli_command_loop (); ++ in_cli = 0; ++ ++ Py_RETURN_NONE; ++} ++ ++/* Set up the Python argument vector and evaluate a script. This is ++ used to implement 'gdb -P'. */ ++ ++void ++run_python_script (int argc, char **argv) ++{ ++ FILE *input; ++ PyGILState_STATE state; ++ ++ /* We never free this, since we plan to exit at the end. */ ++ state = PyGILState_Ensure (); ++ ++ running_python_script = 1; ++ PySys_SetArgv (argc - 1, argv + 1); ++ input = fopen (argv[0], "r"); ++ if (! input) ++ { ++ fprintf (stderr, "could not open %s: %s\n", argv[0], strerror (errno)); ++ exit (1); ++ } ++ PyRun_SimpleFile (input, argv[0]); ++ fclose (input); ++ exit (0); ++} ++ ++void ++source_python_script (FILE *stream, char *file) ++{ ++ PyGILState_STATE state; ++ ++ state = PyGILState_Ensure (); ++ ++ PyRun_SimpleFile (stream, file); ++ ++ fclose (stream); ++ PyGILState_Release (state); ++} ++ ++ ++ ++/* The "current" objfile. This is set when gdb detects that a new ++ objfile has been loaded. It is only set for the duration of a call ++ to gdbpy_new_objfile; it is NULL at other times. */ ++static struct objfile *gdbpy_current_objfile; ++ ++/* The file name we attempt to read. */ ++#define GDBPY_AUTO_FILENAME "-gdb.py" ++ ++/* This is a new_objfile observer callback which loads python code ++ based on the path to the objfile. */ ++static void ++gdbpy_new_objfile (struct objfile *objfile) ++{ ++ char *realname; ++ char *filename, *debugfile; ++ int len; ++ FILE *input; ++ PyGILState_STATE state; ++ struct cleanup *cleanups; ++ ++ if (!gdbpy_auto_load || !objfile || !objfile->name) ++ return; ++ ++ state = PyGILState_Ensure (); ++ ++ gdbpy_current_objfile = objfile; ++ ++ realname = gdb_realpath (objfile->name); ++ len = strlen (realname); ++ filename = xmalloc (len + sizeof (GDBPY_AUTO_FILENAME)); ++ memcpy (filename, realname, len); ++ strcpy (filename + len, GDBPY_AUTO_FILENAME); ++ ++ input = fopen (filename, "r"); ++ debugfile = filename; ++ ++ cleanups = make_cleanup (xfree, filename); ++ make_cleanup (xfree, realname); ++ ++ if (!input && debug_file_directory) ++ { ++ /* Also try the same file in the separate debug info directory. */ ++ debugfile = xmalloc (strlen (filename) ++ + strlen (debug_file_directory) + 1); ++ strcpy (debugfile, debug_file_directory); ++ /* FILENAME is absolute, so we don't need a "/" here. */ ++ strcat (debugfile, filename); ++ ++ make_cleanup (xfree, debugfile); ++ input = fopen (debugfile, "r"); ++ } ++ ++ if (!input && gdb_datadir) ++ { ++ /* Also try the same file in a subdirectory of gdb's data ++ directory. */ ++ debugfile = xmalloc (strlen (gdb_datadir) + strlen (filename) ++ + strlen ("/auto-load") + 1); ++ strcpy (debugfile, gdb_datadir); ++ strcat (debugfile, "/auto-load"); ++ /* FILENAME is absolute, so we don't need a "/" here. */ ++ strcat (debugfile, filename); ++ ++ make_cleanup (xfree, debugfile); ++ input = fopen (debugfile, "r"); ++ } ++ ++ if (input) ++ { ++ /* We don't want to throw an exception here -- but the user ++ would like to know that something went wrong. */ ++ if (PyRun_SimpleFile (input, debugfile)) ++ gdbpy_print_stack (); ++ fclose (input); ++ } ++ ++ do_cleanups (cleanups); ++ gdbpy_current_objfile = NULL; ++ ++ PyGILState_Release (state); ++} ++ ++/* Return the current Objfile, or None if there isn't one. */ ++static PyObject * ++gdbpy_get_current_objfile (PyObject *unused1, PyObject *unused2) ++{ ++ PyObject *result; ++ ++ if (! gdbpy_current_objfile) ++ Py_RETURN_NONE; ++ ++ result = objfile_to_objfile_object (gdbpy_current_objfile); ++ if (result) ++ Py_INCREF (result); ++ return result; ++} ++ ++/* Return a sequence holding all the Objfiles. */ ++static PyObject * ++gdbpy_objfiles (PyObject *unused1, PyObject *unused2) ++{ ++ struct objfile *objf; ++ PyObject *list; ++ ++ list = PyList_New (0); ++ if (!list) ++ return NULL; ++ ++ ALL_OBJFILES (objf) ++ { ++ PyObject *item = objfile_to_objfile_object (objf); ++ if (!item || PyList_Append (list, item) == -1) ++ { ++ Py_DECREF (list); ++ return NULL; ++ } ++ } ++ ++ return list; ++} ++ ++ ++ ++/* Helper function for find_pretty_printer which iterates over a ++ list, calls each function and inspects output. */ ++static PyObject * ++search_pp_list (PyObject *list, PyObject *value) ++{ ++ Py_ssize_t pp_list_size, list_index; ++ PyObject *function, *printer = NULL; ++ ++ pp_list_size = PyList_Size (list); ++ for (list_index = 0; list_index < pp_list_size; list_index++) ++ { ++ function = PyList_GetItem (list, list_index); ++ if (! function) ++ return NULL; ++ ++ /* gdbpy_instantiate_printer can return three possible return ++ values: NULL on error; Py_None if the pretty-printer ++ in the list cannot print the value; or a printer instance if ++ the printer can print the value. */ ++ printer = gdbpy_instantiate_printer (function, value); ++ if (! printer) ++ return NULL; ++ else if (printer != Py_None) ++ return printer; ++ ++ Py_DECREF (printer); ++ } ++ ++ Py_RETURN_NONE; ++} ++ ++/* Find the pretty-printing constructor function for TYPE. If no ++ pretty-printer exists, return NULL. If one exists, return a new ++ reference. */ ++static PyObject * ++find_pretty_printer (PyObject *value) ++{ ++ PyObject *pp_list = NULL; ++ PyObject *function = NULL; ++ struct objfile *obj; ++ volatile struct gdb_exception except; ++ ++ /* Look at the pretty-printer dictionary for each objfile. */ ++ ALL_OBJFILES (obj) ++ { ++ PyObject *objf = objfile_to_objfile_object (obj); ++ if (!objf) ++ continue; ++ ++ pp_list = objfpy_get_printers (objf, NULL); ++ function = search_pp_list (pp_list, value); ++ ++ /* If there is an error in any objfile list, abort the search and ++ exit. */ ++ if (! function) ++ { ++ Py_XDECREF (pp_list); ++ return NULL; ++ } ++ ++ if (function != Py_None) ++ goto done; ++ ++ /* In this loop, if function is not an instantiation of a ++ pretty-printer, and it is not null, then it is a return of ++ Py_RETURN_NONE, which must be decremented. */ ++ Py_DECREF (function); ++ Py_XDECREF (pp_list); ++ } ++ ++ pp_list = NULL; ++ /* Fetch the global pretty printer dictionary. */ ++ if (! PyObject_HasAttrString (gdb_module, "pretty_printers")) ++ goto done; ++ pp_list = PyObject_GetAttrString (gdb_module, "pretty_printers"); ++ if (! pp_list) ++ goto done; ++ if (! PyList_Check (pp_list)) ++ goto done; ++ ++ function = search_pp_list (pp_list, value); ++ ++ done: ++ Py_XDECREF (pp_list); ++ ++ return function; ++} ++ ++/* Pretty-print a single value, via the printer object PRINTER. If ++ the function returns a string, an xmalloc()d copy is returned. ++ Otherwise, if the function returns a value, a *OUT_VALUE is set to ++ the value, and NULL is returned. On error, *OUT_VALUE is set to ++ NULL and NULL is returned. */ ++static char * ++pretty_print_one_value (PyObject *printer, struct value **out_value) ++{ ++ char *output = NULL; ++ volatile struct gdb_exception except; ++ ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ PyObject *result; ++ ++ result = PyObject_CallMethodObjArgs (printer, gdbpy_to_string_cst, NULL); ++ if (result) ++ { ++ if (gdbpy_is_string (result)) ++ output = python_string_to_host_string (result); ++ else if (PyObject_TypeCheck (result, &value_object_type)) ++ { ++ /* If we just call convert_value_from_python for this ++ type, we won't know who owns the result. For this ++ one case we need to copy the resulting value. */ ++ struct value *v = value_object_to_value (result); ++ *out_value = value_copy (v); ++ } ++ else ++ *out_value = convert_value_from_python (result); ++ Py_DECREF (result); ++ } ++ } ++ ++ return output; ++} ++ ++/* Instantiate a pretty-printer given a constructor, CONS, and a ++ value, VAL. Return NULL on error. Ownership of the object ++ instance is transferred to the reciever */ ++PyObject * ++gdbpy_instantiate_printer (PyObject *cons, PyObject *value) ++{ ++ PyObject *result; ++ result = PyObject_CallFunctionObjArgs (cons, value, NULL); ++ return result; ++} ++ ++/* Return the display hint for the object printer, PRINTER. Return ++ NULL if there is no display_hint method, or if the method did not ++ return a string. On error, print stack trace and return NULL. On ++ success, return an xmalloc()d string. */ ++char * ++gdbpy_get_display_hint (PyObject *printer) ++{ ++ PyObject *hint; ++ char *result = NULL; ++ ++ if (! PyObject_HasAttr (printer, gdbpy_display_hint_cst)) ++ return NULL; ++ ++ hint = PyObject_CallMethodObjArgs (printer, gdbpy_display_hint_cst, NULL); ++ if (gdbpy_is_string (hint)) ++ result = python_string_to_host_string (hint); ++ if (hint) ++ Py_DECREF (hint); ++ else ++ gdbpy_print_stack (); ++ ++ return result; ++} ++ ++/* Helper for apply_val_pretty_printer which calls to_string and ++ formats the result. */ ++static void ++print_string_repr (PyObject *printer, const char *hint, ++ struct ui_file *stream, int recurse, ++ const struct value_print_options *options, ++ const struct language_defn *language) ++{ ++ char *output; ++ struct value *replacement = NULL; ++ ++ output = pretty_print_one_value (printer, &replacement); ++ if (output) ++ { ++ if (hint && !strcmp (hint, "string")) ++ { ++ struct type *string_char_type; ++ ++ /* OUTPUT is already in the hosts's charset. */ ++ string_char_type = language_string_char_type (language, ++ current_gdbarch); ++ LA_PRINT_STRING (stream, string_char_type, (gdb_byte *) output, ++ strlen (output), 0, options); ++ } ++ else ++ fputs_filtered (output, stream); ++ xfree (output); ++ } ++ else if (replacement) ++ common_val_print (replacement, stream, recurse, options, language); ++ else ++ gdbpy_print_stack (); ++} ++ ++static void ++py_restore_tstate (void *p) ++{ ++ PyFrameObject *frame = p; ++ PyThreadState *tstate = PyThreadState_GET (); ++ tstate->frame = frame; ++} ++ ++/* Create a dummy PyFrameObject, needed to work around ++ a Python-2.4 bug with generators. */ ++static PyObject * ++push_dummy_python_frame () ++{ ++ PyObject *empty_string, *null_tuple, *globals; ++ PyCodeObject *code; ++ PyFrameObject *frame; ++ PyThreadState *tstate; ++ ++ empty_string = PyString_FromString (""); ++ if (!empty_string) ++ return NULL; ++ ++ null_tuple = PyTuple_New (0); ++ if (!null_tuple) ++ { ++ Py_DECREF (empty_string); ++ return NULL; ++ } ++ ++ code = PyCode_New (0, /* argcount */ ++ 0, /* nlocals */ ++ 0, /* stacksize */ ++ 0, /* flags */ ++ empty_string, /* code */ ++ null_tuple, /* consts */ ++ null_tuple, /* names */ ++ null_tuple, /* varnames */ ++#if PYTHON_API_VERSION >= 1010 ++ null_tuple, /* freevars */ ++ null_tuple, /* cellvars */ ++#endif ++ empty_string, /* filename */ ++ empty_string, /* name */ ++ 1, /* firstlineno */ ++ empty_string /* lnotab */ ++ ); ++ ++ Py_DECREF (empty_string); ++ Py_DECREF (null_tuple); ++ ++ if (!code) ++ return NULL; ++ ++ globals = PyDict_New (); ++ if (!globals) ++ { ++ Py_DECREF (code); ++ return NULL; ++ } ++ ++ tstate = PyThreadState_GET (); ++ ++ frame = PyFrame_New (tstate, code, globals, NULL); ++ ++ Py_DECREF (globals); ++ Py_DECREF (code); ++ ++ if (!frame) ++ return NULL; ++ ++ tstate->frame = frame; ++ make_cleanup (py_restore_tstate, frame->f_back); ++ return (PyObject *) frame; ++} ++ ++/* Helper for apply_val_pretty_printer that formats children of the ++ printer, if any exist. */ ++static void ++print_children (PyObject *printer, const char *hint, ++ struct ui_file *stream, int recurse, ++ const struct value_print_options *options, ++ const struct language_defn *language) ++{ ++ int is_map, is_array, done_flag, pretty; ++ unsigned int i; ++ PyObject *children, *iter, *frame; ++ struct cleanup *cleanups; ++ ++ if (! PyObject_HasAttr (printer, gdbpy_children_cst)) ++ return; ++ ++ /* If we are printing a map or an array, we want some special ++ formatting. */ ++ is_map = hint && ! strcmp (hint, "map"); ++ is_array = hint && ! strcmp (hint, "array"); ++ ++ children = PyObject_CallMethodObjArgs (printer, gdbpy_children_cst, ++ NULL); ++ if (! children) ++ { ++ gdbpy_print_stack (); ++ return; ++ } ++ ++ cleanups = make_cleanup_py_decref (children); ++ ++ iter = PyObject_GetIter (children); ++ if (!iter) ++ { ++ gdbpy_print_stack (); ++ goto done; ++ } ++ make_cleanup_py_decref (iter); ++ ++ /* Use the prettyprint_arrays option if we are printing an array, ++ and the pretty option otherwise. */ ++ pretty = is_array ? options->prettyprint_arrays : options->pretty; ++ ++ /* Manufacture a dummy Python frame to work around Python 2.4 bug, ++ where it insists on having a non-NULL tstate->frame when ++ a generator is called. */ ++ frame = push_dummy_python_frame (); ++ if (!frame) ++ { ++ gdbpy_print_stack (); ++ goto done; ++ } ++ make_cleanup_py_decref (frame); ++ ++ done_flag = 0; ++ for (i = 0; i < options->print_max; ++i) ++ { ++ PyObject *py_v, *item = PyIter_Next (iter); ++ char *name; ++ struct cleanup *inner_cleanup; ++ ++ if (! item) ++ { ++ if (PyErr_Occurred ()) ++ gdbpy_print_stack (); ++ /* Set a flag so we can know whether we printed all the ++ available elements. */ ++ else ++ done_flag = 1; ++ break; ++ } ++ ++ if (! PyArg_ParseTuple (item, "sO", &name, &py_v)) ++ { ++ gdbpy_print_stack (); ++ Py_DECREF (item); ++ continue; ++ } ++ inner_cleanup = make_cleanup_py_decref (item); ++ ++ /* Print initial "{". For other elements, there are three ++ cases: ++ 1. Maps. Print a "," after each value element. ++ 2. Arrays. Always print a ",". ++ 3. Other. Always print a ",". */ ++ if (i == 0) ++ fputs_filtered (" = {", stream); ++ else if (! is_map || i % 2 == 0) ++ fputs_filtered (pretty ? "," : ", ", stream); ++ ++ /* In summary mode, we just want to print "= {...}" if there is ++ a value. */ ++ if (options->summary) ++ { ++ /* This increment tricks the post-loop logic to print what ++ we want. */ ++ ++i; ++ /* Likewise. */ ++ pretty = 0; ++ break; ++ } ++ ++ if (! is_map || i % 2 == 0) ++ { ++ if (pretty) ++ { ++ fputs_filtered ("\n", stream); ++ print_spaces_filtered (2 + 2 * recurse, stream); ++ } ++ else ++ wrap_here (n_spaces (2 + 2 *recurse)); ++ } ++ ++ if (is_map && i % 2 == 0) ++ fputs_filtered ("[", stream); ++ else if (is_array) ++ { ++ /* We print the index, not whatever the child method ++ returned as the name. */ ++ if (options->print_array_indexes) ++ fprintf_filtered (stream, "[%d] = ", i); ++ } ++ else if (! is_map) ++ { ++ fputs_filtered (name, stream); ++ fputs_filtered (" = ", stream); ++ } ++ ++ if (gdbpy_is_string (py_v)) ++ { ++ char *text = python_string_to_host_string (py_v); ++ if (! text) ++ gdbpy_print_stack (); ++ else ++ { ++ fputs_filtered (text, stream); ++ xfree (text); ++ } ++ } ++ else ++ { ++ struct value *value = convert_value_from_python (py_v); ++ ++ if (value == NULL) ++ { ++ gdbpy_print_stack (); ++ error (_("Error while executing Python code.")); ++ } ++ else ++ common_val_print (value, stream, recurse + 1, options, language); ++ } ++ ++ if (is_map && i % 2 == 0) ++ fputs_filtered ("] = ", stream); ++ ++ do_cleanups (inner_cleanup); ++ } ++ ++ if (i) ++ { ++ if (!done_flag) ++ { ++ if (pretty) ++ { ++ fputs_filtered ("\n", stream); ++ print_spaces_filtered (2 + 2 * recurse, stream); ++ } ++ fputs_filtered ("...", stream); ++ } ++ if (pretty) ++ { ++ fputs_filtered ("\n", stream); ++ print_spaces_filtered (2 * recurse, stream); ++ } ++ fputs_filtered ("}", stream); ++ } ++ ++ done: ++ do_cleanups (cleanups); ++} ++ ++int ++apply_val_pretty_printer (struct type *type, const gdb_byte *valaddr, ++ int embedded_offset, CORE_ADDR address, ++ struct ui_file *stream, int recurse, ++ const struct value_print_options *options, ++ const struct language_defn *language) ++{ ++ PyObject *printer = NULL; ++ PyObject *val_obj = NULL; ++ struct value *value; ++ char *hint = NULL; ++ struct cleanup *cleanups; ++ int result = 0; ++ PyGILState_STATE state; ++ ++ state = PyGILState_Ensure (); ++ cleanups = make_cleanup_py_restore_gil (&state); ++ ++ /* Instantiate the printer. */ ++ if (valaddr) ++ valaddr += embedded_offset; ++ value = value_from_contents_and_address (type, valaddr, address); ++ ++ val_obj = value_to_value_object (value); ++ if (! val_obj) ++ goto done; ++ ++ /* Find the constructor. */ ++ printer = find_pretty_printer (val_obj); ++ Py_DECREF (val_obj); ++ make_cleanup_py_decref (printer); ++ if (! printer || printer == Py_None) ++ goto done; ++ ++ /* If we are printing a map, we want some special formatting. */ ++ hint = gdbpy_get_display_hint (printer); ++ make_cleanup (free_current_contents, &hint); ++ ++ /* Print the section */ ++ print_string_repr (printer, hint, stream, recurse, options, language); ++ print_children (printer, hint, stream, recurse, options, language); ++ result = 1; ++ ++ ++ done: ++ if (PyErr_Occurred ()) ++ gdbpy_print_stack (); ++ do_cleanups (cleanups); ++ return result; ++} ++ ++/* Apply a pretty-printer for the varobj code. PRINTER_OBJ is the ++ print object. It must have a 'to_string' method (but this is ++ checked by varobj, not here) which takes no arguments and ++ returns a string. This function returns an xmalloc()d string if ++ the printer returns a string. The printer may return a replacement ++ value instead; in this case *REPLACEMENT is set to the replacement ++ value, and this function returns NULL. On error, *REPLACEMENT is ++ set to NULL and this function also returns NULL. */ ++char * ++apply_varobj_pretty_printer (PyObject *printer_obj, ++ struct value **replacement) ++{ ++ char *result; ++ PyGILState_STATE state = PyGILState_Ensure (); ++ ++ *replacement = NULL; ++ result = pretty_print_one_value (printer_obj, replacement); ++ if (result == NULL); ++ gdbpy_print_stack (); ++ PyGILState_Release (state); ++ ++ return result; ++} ++ ++/* Find a pretty-printer object for the varobj module. Returns a new ++ reference to the object if successful; returns NULL if not. VALUE ++ is the value for which a printer tests to determine if it ++ can pretty-print the value. */ ++PyObject * ++gdbpy_get_varobj_pretty_printer (struct value *value) ++{ ++ PyObject *val_obj; ++ PyObject *pretty_printer = NULL; ++ volatile struct gdb_exception except; ++ ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ value = value_copy (value); ++ } ++ GDB_PY_HANDLE_EXCEPTION (except); ++ ++ val_obj = value_to_value_object (value); ++ if (! val_obj) ++ return NULL; ++ ++ pretty_printer = find_pretty_printer (val_obj); ++ Py_DECREF (val_obj); ++ return pretty_printer; ++} ++ ++/* A Python function which wraps find_pretty_printer and instantiates ++ the resulting class. This accepts a Value argument and returns a ++ pretty printer instance, or None. This function is useful as an ++ argument to the MI command -var-set-visualizer. */ ++static PyObject * ++gdbpy_default_visualizer (PyObject *self, PyObject *args) ++{ ++ PyObject *val_obj; ++ PyObject *cons, *printer = NULL; ++ struct value *value; ++ ++ if (! PyArg_ParseTuple (args, "O", &val_obj)) ++ return NULL; ++ value = value_object_to_value (val_obj); ++ if (! value) ++ { ++ PyErr_SetString (PyExc_TypeError, "argument must be a gdb.Value"); ++ return NULL; ++ } ++ ++ cons = find_pretty_printer (val_obj); ++ return cons; ++} ++ + #else /* HAVE_PYTHON */ + + /* Dummy implementation of the gdb "python" command. */ +@@ -328,6 +1677,24 @@ eval_python_from_control_command (struct command_line *cmd) + error (_("Python scripting is not supported in this copy of GDB.")); + } + ++int ++apply_val_pretty_printer (struct type *type, const gdb_byte *valaddr, ++ int embedded_offset, CORE_ADDR address, ++ struct ui_file *stream, int format, ++ int deref_ref, int recurse, ++ enum val_prettyprint pretty, ++ const struct language_defn *language) ++{ ++ return 0; ++} ++ ++void ++source_python_script (FILE *stream) ++{ ++ fclose (stream); ++ error (_("Python scripting is not supported in this copy of GDB.")); ++} ++ + #endif /* HAVE_PYTHON */ + + +@@ -355,9 +1722,6 @@ show_python (char *args, int from_tty) + + /* Initialize the Python code. */ + +-/* Provide a prototype to silence -Wmissing-prototypes. */ +-extern initialize_file_ftype _initialize_python; +- + void + _initialize_python (void) + { +@@ -400,6 +1764,15 @@ Enables or disables printing of Python stack traces."), + &set_python_list, + &show_python_list); + ++ add_setshow_boolean_cmd ("auto-load", class_maintenance, ++ &gdbpy_auto_load, _("\ ++Enable or disable auto-loading of Python code when an object is opened."), _("\ ++Show whether Python code will be auto-loaded when an object is opened."), _("\ ++Enables or disables auto-loading of Python code when an object is opened."), ++ NULL, NULL, ++ &set_python_list, ++ &show_python_list); ++ + #ifdef HAVE_PYTHON + Py_Initialize (); + PyEval_InitThreads (); +@@ -410,11 +1783,36 @@ Enables or disables printing of Python stack traces."), + PyModule_AddStringConstant (gdb_module, "VERSION", (char*) version); + PyModule_AddStringConstant (gdb_module, "HOST_CONFIG", (char*) host_name); + PyModule_AddStringConstant (gdb_module, "TARGET_CONFIG", (char*) target_name); ++#ifdef PYTHONDIR ++ PyModule_AddStringConstant (gdb_module, "pythondir", PYTHONDIR); ++#else ++ if (gdb_datadir) ++ PyModule_AddStringConstant (gdb_module, "datadir", gdb_datadir); ++#endif + + gdbpy_initialize_values (); ++ gdbpy_initialize_breakpoints (); ++ gdbpy_initialize_frames (); ++ gdbpy_initialize_symtabs (); + gdbpy_initialize_commands (); ++ gdbpy_initialize_symbols (); ++ gdbpy_initialize_blocks (); ++ gdbpy_initialize_functions (); ++ gdbpy_initialize_types (); ++ gdbpy_initialize_parameters (); ++ gdbpy_initialize_objfile (); ++ gdbpy_initialize_events (); ++ gdbpy_initialize_membuf (); + + PyRun_SimpleString ("import gdb"); ++ PyRun_SimpleString ("gdb.pretty_printers = []"); ++ ++ observer_attach_new_objfile (gdbpy_new_objfile); ++ ++ gdbpy_to_string_cst = PyString_FromString ("to_string"); ++ gdbpy_children_cst = PyString_FromString ("children"); ++ gdbpy_display_hint_cst = PyString_FromString ("display_hint"); ++ gdbpy_doc_cst = PyString_FromString ("__doc__"); + + gdbpy_doc_cst = PyString_FromString ("__doc__"); + +@@ -442,6 +1840,15 @@ class GdbOutputFile:\n\ + \n\ + sys.stderr = GdbOutputFile()\n\ + sys.stdout = GdbOutputFile()\n\ ++if hasattr (gdb, 'datadir'):\n\ ++ gdb.pythondir = gdb.datadir + '/python'\n\ ++if hasattr (gdb, 'pythondir'):\n\ ++ sys.path.insert(0, gdb.pythondir)\n\ ++ gdb.__path__ = [gdb.pythondir + '/gdb']\n\ ++ from os.path import exists\n\ ++ ipy = gdb.pythondir + '/gdb/__init__.py'\n\ ++ if exists (ipy):\n\ ++ execfile (ipy)\n\ + "); + + /* Release the GIL while gdb runs. */ +@@ -461,9 +1868,79 @@ static PyMethodDef GdbMethods[] = + "Get a value from history" }, + { "execute", execute_gdb_command, METH_VARARGS, + "Execute a gdb command" }, +- { "get_parameter", get_parameter, METH_VARARGS, ++ { "cli", gdbpy_cli, METH_NOARGS, ++ "Enter the gdb CLI" }, ++ { "parameter", gdbpy_parameter, METH_VARARGS, + "Return a gdb parameter's value" }, + ++ { "breakpoints", gdbpy_breakpoints, METH_NOARGS, ++ "Return a tuple of all breakpoint objects" }, ++ ++ { "default_visualizer", gdbpy_default_visualizer, METH_VARARGS, ++ "Find the default visualizer for a Value." }, ++ ++ { "current_objfile", gdbpy_get_current_objfile, METH_NOARGS, ++ "Return the current Objfile being loaded, or None." }, ++ { "objfiles", gdbpy_objfiles, METH_NOARGS, ++ "Return a sequence of all loaded objfiles." }, ++ ++ { "frames", gdbpy_frames, METH_NOARGS, ++ "frames () -> (gdb.Frame, ...).\n\ ++Return a tuple of all frame objects." }, ++ { "newest_frame", gdbpy_newest_frame, METH_NOARGS, ++ "newest_frame () -> gdb.Frame.\n\ ++Return the newest frame object." }, ++ { "selected_frame", gdbpy_selected_frame, METH_NOARGS, ++ "selected_frame () -> gdb.Frame.\n\ ++Return the selected frame object." }, ++ { "frame_stop_reason_string", gdbpy_frame_stop_reason_string, METH_VARARGS, ++ "stop_reason_string (Integer) -> String.\n\ ++Return a string explaining unwind stop reason." }, ++ ++ { "lookup_symbol", (PyCFunction) gdbpy_lookup_symbol, ++ METH_VARARGS | METH_KEYWORDS, ++ "lookup_symbol (name [, block] [, domain]) -> (symbol, is_field_of_this)\n\ ++Return a tuple with the symbol corresponding to the given name (or None) and\n\ ++a boolean indicating if name is a field of the current implied argument\n\ ++`this' (when the current language is object-oriented)." }, ++ { "solib_address", gdbpy_solib_address, METH_VARARGS, ++ "solib_address (Long) -> String.\n\ ++Return the name of the shared library holding a given address, or None." }, ++ ++ { "find_pc_function", gdbpy_find_pc_function, METH_VARARGS, ++ "Return the function containing the given pc value, or None." }, ++ ++ { "block_for_pc", gdbpy_block_for_pc, METH_VARARGS, ++ "Return the block containing the given pc value, or None." }, ++ ++ { "decode_line", gdbpy_decode_line, METH_VARARGS, ++ "Decode a string argument the way that 'break' or 'edit' does.\n\ ++Return a tuple holding the file name (or None) and line number (or None).\n\ ++Note: may later change to return an object." }, ++ ++ { "threads", gdbpy_threads, METH_NOARGS, ++ "Return a tuple holding all the valid thread IDs." }, ++ { "current_thread", gdbpy_current_thread, METH_NOARGS, ++ "Return the thread ID of the current thread." }, ++ { "switch_to_thread", gdbpy_switch_to_thread, METH_VARARGS, ++ "Switch to a thread, given the thread ID." }, ++ ++ { "parse_and_eval", gdbpy_parse_and_eval, METH_VARARGS, ++ "Parse a string as an expression, evaluate it, and return the result." }, ++ ++ { "post_event", gdbpy_post_event, METH_VARARGS, ++ "Post an event into gdb's event loop." }, ++ ++ { "read_memory", gdbpy_read_memory, METH_VARARGS, ++ "read_memory (address, length) -> buffer\n\ ++Return a buffer object for reading from the inferior's memory." }, ++ { "write_memory", gdbpy_write_memory, METH_VARARGS, ++ "write_memory (address, buffer [, length])\n\ ++Write the given buffer object to the inferior's memory." }, ++ { "search_memory", (PyCFunction) gdbpy_search_memory, METH_VARARGS | METH_KEYWORDS, ++ "search_memory (address, length, pattern [, size] [, max_count]) -> list\n\ ++Return a list with the addresses where matches were found." }, ++ + { "write", gdbpy_write, METH_VARARGS, + "Write a string using gdb's filtered stream." }, + { "flush", gdbpy_flush, METH_NOARGS, +diff --git a/gdb/python/python.h b/gdb/python/python.h +index e63c447..767af86 100644 +--- a/gdb/python/python.h ++++ b/gdb/python/python.h +@@ -26,4 +26,14 @@ extern struct value *values_in_python; + + void eval_python_from_control_command (struct command_line *); + ++void source_python_script (FILE *stream, char *file); ++ ++void run_python_script (int argc, char **argv); ++ ++int apply_val_pretty_printer (struct type *type, const gdb_byte *valaddr, ++ int embedded_offset, CORE_ADDR address, ++ struct ui_file *stream, int recurse, ++ const struct value_print_options *options, ++ const struct language_defn *language); ++ + #endif /* GDB_PYTHON_H */ +diff --git a/gdb/scm-lang.c b/gdb/scm-lang.c +index 345befd..e2568c8 100644 +--- a/gdb/scm-lang.c ++++ b/gdb/scm-lang.c +@@ -43,14 +43,14 @@ static int in_eval_c (void); + struct type *builtin_type_scm; + + void +-scm_printchar (int c, struct ui_file *stream) ++scm_printchar (int c, struct type *type, struct ui_file *stream) + { + fprintf_filtered (stream, "#\\%c", c); + } + + static void +-scm_printstr (struct ui_file *stream, const gdb_byte *string, +- unsigned int length, int width, int force_ellipses, ++scm_printstr (struct ui_file *stream, struct type *type, const gdb_byte *string, ++ unsigned int length, int force_ellipses, + const struct value_print_options *options) + { + fprintf_filtered (stream, "\"%s\"", string); +diff --git a/gdb/scm-lang.h b/gdb/scm-lang.h +index 6bf88f5..1798b2f 100644 +--- a/gdb/scm-lang.h ++++ b/gdb/scm-lang.h +@@ -59,7 +59,7 @@ extern void scm_scmval_print (LONGEST, struct ui_file *, int, + + extern int is_scmvalue_type (struct type *); + +-extern void scm_printchar (int, struct ui_file *); ++extern void scm_printchar (int, struct type *, struct ui_file *); + + extern struct value *scm_evaluate_string (char *, int); + +diff --git a/gdb/scm-valprint.c b/gdb/scm-valprint.c +index f0a7642..a32add5 100644 +--- a/gdb/scm-valprint.c ++++ b/gdb/scm-valprint.c +@@ -187,7 +187,8 @@ taloop: + if (SCM_ICHRP (svalue)) + { + svalue = SCM_ICHR (svalue); +- scm_printchar (svalue, stream); ++ scm_printchar (svalue, builtin_type (current_gdbarch)->builtin_char, ++ stream); + break; + } + else if (SCM_IFLAGP (svalue) +diff --git a/gdb/stabsread.c b/gdb/stabsread.c +index 2d7eb15..7423b32 100644 +--- a/gdb/stabsread.c ++++ b/gdb/stabsread.c +@@ -322,7 +322,7 @@ dbx_alloc_type (int typenums[2], struct objfile *objfile) + + if (typenums[0] == -1) + { +- return (alloc_type (objfile)); ++ return (alloc_type (objfile, NULL)); + } + + type_addr = dbx_lookup_type (typenums); +@@ -332,7 +332,7 @@ dbx_alloc_type (int typenums[2], struct objfile *objfile) + We will fill it in later if we find out how. */ + if (*type_addr == 0) + { +- *type_addr = alloc_type (objfile); ++ *type_addr = alloc_type (objfile, NULL); + } + + return (*type_addr); +@@ -589,6 +589,7 @@ define_symbol (CORE_ADDR valu, char *string, int desc, int type, + int deftype; + int synonym = 0; + int i; ++ char *new_name = NULL; + + /* We would like to eliminate nameless symbols, but keep their types. + E.g. stab entry ":t10=*2" should produce a type 10, which is a pointer +@@ -683,9 +684,37 @@ define_symbol (CORE_ADDR valu, char *string, int desc, int type, + { + normal: + SYMBOL_LANGUAGE (sym) = current_subfile->language; +- SYMBOL_SET_NAMES (sym, string, p - string, objfile); ++ if (current_subfile->language == language_cplus) ++ { ++ char *name = alloca (p - string + 1); ++ memcpy (name, string, p - string); ++ name[p - string] = '\0'; ++ new_name = cp_canonicalize_string (name); ++ } ++ ++ if (new_name != NULL) ++ { ++ SYMBOL_SET_NAMES (sym, new_name, strlen (new_name), objfile); ++ xfree (new_name); ++ } ++ else ++ SYMBOL_SET_NAMES (sym, string, p - string, objfile); ++ + if (SYMBOL_LANGUAGE (sym) == language_cplus) +- cp_scan_for_anonymous_namespaces (sym); ++ { ++ char *name = alloca (p - string + 1); ++ memcpy (name, string, p - string); ++ name[p - string] = '\0'; ++ new_name = cp_canonicalize_string (name); ++ cp_scan_for_anonymous_namespaces (sym); ++ } ++ if (new_name != NULL) ++ { ++ SYMBOL_SET_NAMES (sym, new_name, strlen (new_name), objfile); ++ xfree (new_name); ++ } ++ else ++ SYMBOL_SET_NAMES (sym, string, p - string, objfile); + } + p++; + +@@ -1519,18 +1548,35 @@ again: + if (*p != ':') + return error_type (pp, objfile); + } +- to = type_name = +- (char *) obstack_alloc (&objfile->objfile_obstack, p - *pp + 1); +- +- /* Copy the name. */ +- from = *pp + 1; +- while (from < p) +- *to++ = *from++; +- *to = '\0'; ++ type_name = NULL; ++ if (current_subfile->language == language_cplus) ++ { ++ char *new_name, *name = alloca (p - *pp + 1); ++ memcpy (name, *pp, p - *pp); ++ name[p - *pp] = '\0'; ++ new_name = cp_canonicalize_string (name); ++ if (new_name != NULL) ++ { ++ type_name = obsavestring (new_name, strlen (new_name), ++ &objfile->objfile_obstack); ++ xfree (new_name); ++ } ++ } ++ if (type_name == NULL) ++ { ++ to = type_name = ++ (char *) obstack_alloc (&objfile->objfile_obstack, p - *pp + 1); ++ ++ /* Copy the name. */ ++ from = *pp + 1; ++ while (from < p) ++ *to++ = *from++; ++ *to = '\0'; ++ } + + /* Set the pointer ahead of the name which we just read, and + the colon. */ +- *pp = from + 1; ++ *pp = p + 1; + } + + /* If this type has already been declared, then reuse the same +diff --git a/gdb/stack.c b/gdb/stack.c +index 3bcf758..fa7fc61 100644 +--- a/gdb/stack.c ++++ b/gdb/stack.c +@@ -380,6 +380,7 @@ print_frame_args (struct symbol *func, struct frame_info *frame, + + get_raw_print_options (&opts); + opts.deref_ref = 0; ++ opts.summary = 1; + common_val_print (val, stb->stream, 2, + &opts, language); + ui_out_field_stream (uiout, "value", stb); +@@ -579,20 +580,16 @@ print_frame_info (struct frame_info *frame, int print_level, + gdb_flush (gdb_stdout); + } + +-static void +-print_frame (struct frame_info *frame, int print_level, +- enum print_what print_what, int print_args, +- struct symtab_and_line sal) ++/* Attempt to obtain the FUNNAME and FUNLANG of the function corresponding ++ to FRAME. */ ++void ++find_frame_funname (struct frame_info *frame, char **funname, ++ enum language *funlang) + { + struct symbol *func; +- char *funname = NULL; +- enum language funlang = language_unknown; +- struct ui_stream *stb; +- struct cleanup *old_chain, *list_chain; +- struct value_print_options opts; + +- stb = ui_out_stream_new (uiout); +- old_chain = make_cleanup_ui_out_stream_delete (stb); ++ *funname = NULL; ++ *funlang = language_unknown; + + func = find_pc_function (get_frame_address_in_block (frame)); + if (func) +@@ -625,24 +622,24 @@ print_frame (struct frame_info *frame, int print_level, + /* We also don't know anything about the function besides + its address and name. */ + func = 0; +- funname = SYMBOL_PRINT_NAME (msymbol); +- funlang = SYMBOL_LANGUAGE (msymbol); ++ *funname = SYMBOL_PRINT_NAME (msymbol); ++ *funlang = SYMBOL_LANGUAGE (msymbol); + } + else + { +- funname = SYMBOL_PRINT_NAME (func); +- funlang = SYMBOL_LANGUAGE (func); +- if (funlang == language_cplus) ++ *funname = SYMBOL_PRINT_NAME (func); ++ *funlang = SYMBOL_LANGUAGE (func); ++ if (*funlang == language_cplus) + { + /* It seems appropriate to use SYMBOL_PRINT_NAME() here, + to display the demangled name that we already have + stored in the symbol table, but we stored a version + with DMGL_PARAMS turned on, and here we don't want to + display parameters. So remove the parameters. */ +- char *func_only = cp_remove_params (funname); ++ char *func_only = cp_remove_params (*funname); + if (func_only) + { +- funname = func_only; ++ *funname = func_only; + make_cleanup (xfree, func_only); + } + } +@@ -655,10 +652,27 @@ print_frame (struct frame_info *frame, int print_level, + + if (msymbol != NULL) + { +- funname = SYMBOL_PRINT_NAME (msymbol); +- funlang = SYMBOL_LANGUAGE (msymbol); ++ *funname = SYMBOL_PRINT_NAME (msymbol); ++ *funlang = SYMBOL_LANGUAGE (msymbol); + } + } ++} ++ ++static void ++print_frame (struct frame_info *frame, int print_level, ++ enum print_what print_what, int print_args, ++ struct symtab_and_line sal) ++{ ++ char *funname = NULL; ++ enum language funlang = language_unknown; ++ struct ui_stream *stb; ++ struct cleanup *old_chain, *list_chain; ++ struct value_print_options opts; ++ ++ stb = ui_out_stream_new (uiout); ++ old_chain = make_cleanup_ui_out_stream_delete (stb); ++ ++ find_frame_funname (frame, &funname, &funlang); + + annotate_frame_begin (print_level ? frame_relative_level (frame) : 0, + get_frame_pc (frame)); +@@ -694,7 +708,7 @@ print_frame (struct frame_info *frame, int print_level, + struct print_args_args args; + struct cleanup *args_list_chain; + args.frame = frame; +- args.func = func; ++ args.func = find_pc_function (get_frame_address_in_block (frame)); + args.stream = gdb_stdout; + args_list_chain = make_cleanup_ui_out_list_begin_end (uiout, "args"); + catch_errors (print_args_stub, &args, "", RETURN_MASK_ERROR); +@@ -1208,24 +1222,24 @@ backtrace_command_1 (char *count_exp, int show_locals, int from_tty) + else + count = -1; + +- if (info_verbose) +- { +- struct partial_symtab *ps; +- +- /* Read in symbols for all of the frames. Need to do this in a +- separate pass so that "Reading in symbols for xxx" messages +- don't screw up the appearance of the backtrace. Also if +- people have strong opinions against reading symbols for +- backtrace this may have to be an option. */ +- i = count; +- for (fi = trailing; fi != NULL && i--; fi = get_prev_frame (fi)) +- { +- QUIT; +- ps = find_pc_psymtab (get_frame_address_in_block (fi)); +- if (ps) +- PSYMTAB_TO_SYMTAB (ps); /* Force syms to come in. */ +- } +- } ++ { ++ struct partial_symtab *ps; ++ ++ /* Read in symbols for all of the frames. Need to do this ++ unconditionally to ensure that psymbols are read. Also need to ++ do this in a separate pass so that "Reading in symbols for xxx" ++ messages don't screw up the appearance of the backtrace. Also ++ if people have strong opinions against reading symbols for ++ backtrace this may have to be an option. */ ++ i = count; ++ for (fi = trailing; fi != NULL && i--; fi = get_prev_frame (fi)) ++ { ++ QUIT; ++ ps = find_pc_psymtab (get_frame_address_in_block (fi)); ++ if (info_verbose && ps) ++ PSYMTAB_TO_SYMTAB (ps); /* Force syms to come in. */ ++ } ++ } + + for (i = 0, fi = trailing; fi && count--; i++, fi = get_prev_frame (fi)) + { +@@ -1373,6 +1387,8 @@ print_block_frame_locals (struct block *b, struct frame_info *frame, + case LOC_COMPUTED: + if (SYMBOL_IS_ARGUMENT (sym)) + break; ++ if (SYMBOL_DOMAIN (sym) == COMMON_BLOCK_DOMAIN) ++ break; + values_printed = 1; + print_variable_and_value (NULL, sym, frame, stream, 4 * num_tabs); + break; +@@ -1777,7 +1793,75 @@ down_command (char *count_exp, int from_tty) + down_silently_base (count_exp); + print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC); + } +- ++ ++/* Verify whether if RETURN_VALUE width gets extended to EXT_TYPE it will still ++ be the same value after reading it back using the RETURN_VALUE type. */ ++ ++static int ++return_extended_value_cast (struct value *return_value, struct type *ext_type) ++{ ++ struct regcache *current_regcache = get_current_regcache (); ++ struct gdbarch *gdbarch = get_regcache_arch (current_regcache); ++ struct type *return_type = value_type (return_value); ++ struct value *ext_value, *compare_value; ++ ++ if (gdbarch_return_value (gdbarch, NULL, ext_type, NULL, NULL, NULL) ++ != RETURN_VALUE_REGISTER_CONVENTION) ++ return 0; ++ ++ ext_value = value_cast (ext_type, return_value); ++ gdbarch_return_value (gdbarch, NULL, ext_type, ++ current_regcache, NULL /*read*/, ++ value_contents (ext_value) /*write*/); ++ ++ compare_value = allocate_value (return_type); ++ gdbarch_return_value (gdbarch, NULL, return_type, current_regcache, ++ value_contents_raw (compare_value) /*read*/, ++ NULL /*write*/); ++ ++ return value_equal (return_value, compare_value); ++} ++ ++/* Set RETURN_VALUE extended to the largest type width which will still be the ++ same value after reading it back using the RETURN_VALUE type. */ ++ ++static void ++return_extended_value (struct value *return_value) ++{ ++ struct type *return_type = value_type (return_value); ++ struct regcache *current_regcache = get_current_regcache (); ++ struct gdbarch *gdbarch = get_regcache_arch (current_regcache); ++ const struct builtin_type *builtins = builtin_type (gdbarch); ++ struct type **extp, *ext_tab[] = ++ { ++ builtins->builtin_long_long, ++ builtins->builtin_long, ++ return_type ++ }; ++ unsigned width_tried = 0; ++ ++ for (extp = ext_tab; extp < ext_tab + ARRAY_SIZE (ext_tab); extp++) ++ { ++ struct type *ext_type = *extp; ++ ++ /* Do not retry extension to the integer of an already tried width. */ ++ if (ext_type != return_type && width_tried == TYPE_LENGTH (ext_type)) ++ continue; ++ ++ /* Do not extend to non-original smaller (or the same size) type. */ ++ if (ext_type != return_type ++ && TYPE_LENGTH (ext_type) <= TYPE_LENGTH (return_type)) ++ continue; ++ ++ gdb_assert (TYPE_LENGTH (return_type) <= TYPE_LENGTH (ext_type)); ++ width_tried = TYPE_LENGTH (ext_type); ++ if (return_extended_value_cast (return_value, ext_type)) ++ break; ++ } ++ ++ /* Ensure at least the attempt with original RETURN_TYPE was successful. */ ++ gdb_assert (extp < ext_tab + ARRAY_SIZE (ext_tab)); ++} + + void + return_command (char *retval_exp, int from_tty) +@@ -1806,6 +1890,8 @@ return_command (char *retval_exp, int from_tty) + the cast fail, this call throws an error. */ + if (thisfun != NULL) + return_type = TYPE_TARGET_TYPE (SYMBOL_TYPE (thisfun)); ++ else ++ return_type = value_type (return_value); + if (return_type == NULL) + return_type = builtin_type (get_frame_arch (thisframe))->builtin_int; + CHECK_TYPEDEF (return_type); +@@ -1862,9 +1948,13 @@ If you continue, the return value that you specified will be ignored.\n"; + gdb_assert (gdbarch_return_value (gdbarch, func_type, return_type, NULL, + NULL, NULL) + == RETURN_VALUE_REGISTER_CONVENTION); +- gdbarch_return_value (gdbarch, func_type, return_type, +- get_current_regcache (), NULL /*read*/, +- value_contents (return_value) /*write*/); ++ ++ if (thisfun != NULL) ++ gdbarch_return_value (gdbarch, func_type, return_type, ++ get_current_regcache (), NULL /*read*/, ++ value_contents (return_value) /*write*/); ++ else ++ return_extended_value (return_value); + } + + /* If we are at the end of a call dummy now, pop the dummy frame +diff --git a/gdb/stack.h b/gdb/stack.h +index 973a57f..56b1d91 100644 +--- a/gdb/stack.h ++++ b/gdb/stack.h +@@ -22,4 +22,9 @@ + + void select_frame_command (char *level_exp, int from_tty); + ++/* Attempt to obtain the FUNNAME and FUNLANG of the function corresponding ++ to FRAME. */ ++void find_frame_funname (struct frame_info *frame, char **funname, ++ enum language *funlang); ++ + #endif /* #ifndef STACK_H */ +diff --git a/gdb/symfile.c b/gdb/symfile.c +index 63b5c1d..b047e94 100644 +--- a/gdb/symfile.c ++++ b/gdb/symfile.c +@@ -929,6 +929,17 @@ new_symfile_objfile (struct objfile *objfile, int mainline, int verbo) + clear_complaints (&symfile_complaints, 0, verbo); + } + ++/* A helper function which returns true if OBJFILE has any debug ++ symbols, and false otherwise. */ ++static int ++has_any_debug_symbols (struct objfile *objfile) ++{ ++ return (objfile->psymtabs || objfile->quick_addrmap ++ || (objfile->separate_debug_objfile ++ && (objfile->separate_debug_objfile->psymtabs ++ || objfile->separate_debug_objfile->quick_addrmap))); ++} ++ + /* Process a symbol file, as either the main file or as a dynamically + loaded file. + +@@ -965,13 +976,15 @@ symbol_file_add_with_addrs_or_offsets (bfd *abfd, int from_tty, + /* Give user a chance to burp if we'd be + interactively wiping out any existing symbols. */ + +- if ((have_full_symbols () || have_partial_symbols ()) +- && mainline ++ if (mainline + && from_tty ++ && (have_full_symbols () || have_partial_symbols ()) + && !query (_("Load new symbol table from \"%s\"? "), name)) + error (_("Not confirmed.")); + + objfile = allocate_objfile (abfd, flags); ++ if (mainline) ++ objfile->flags |= OBJF_MAIN; + discard_cleanups (my_cleanups); + + if (addrs) +@@ -1007,6 +1020,8 @@ symbol_file_add_with_addrs_or_offsets (bfd *abfd, int from_tty, + + if ((flags & OBJF_READNOW) || readnow_symbol_files) + { ++ require_partial_symbols (objfile); ++ + if ((from_tty || info_verbose) && print_symbol_loading) + { + printf_unfiltered (_("expanding to full symbols...")); +@@ -1025,7 +1040,7 @@ symbol_file_add_with_addrs_or_offsets (bfd *abfd, int from_tty, + /* If the file has its own symbol tables it has no separate debug info. + `.dynsym'/`.symtab' go to MSYMBOLS, `.debug_info' goes to SYMTABS/PSYMTABS. + `.gnu_debuglink' may no longer be present with `.note.gnu.build-id'. */ +- if (objfile->psymtabs == NULL) ++ if (!has_any_debug_symbols (objfile)) + debugfile = find_separate_debug_file (objfile); + if (debugfile) + { +@@ -1049,8 +1064,10 @@ symbol_file_add_with_addrs_or_offsets (bfd *abfd, int from_tty, + xfree (debugfile); + } + +- if (!have_partial_symbols () && !have_full_symbols () +- && print_symbol_loading) ++ /* has_any_debug_symbols is not fully compatible with the former calls which ++ would just be needlessly expensive here. */ ++ if ((from_tty || info_verbose) && print_symbol_loading ++ && !has_any_debug_symbols (objfile) && mainline) + { + wrap_here (""); + printf_unfiltered (_("(no debugging symbols found)")); +@@ -2423,13 +2440,15 @@ reread_symbols (void) + zero is OK since dbxread.c also does what it needs to do if + objfile->global_psymbols.size is 0. */ + (*objfile->sf->sym_read) (objfile, 0); +- if (!have_partial_symbols () && !have_full_symbols ()) ++ if (!has_any_debug_symbols (objfile)) + { + wrap_here (""); + printf_unfiltered (_("(no debugging symbols found)\n")); + wrap_here (""); + } + ++ objfile->flags &= ~OBJF_SYMTABS_READ; ++ + /* We're done reading the symbol file; finish off complaints. */ + clear_complaints (&symfile_complaints, 0, 1); + +@@ -2726,7 +2745,7 @@ allocate_symtab (char *filename, struct objfile *objfile) + } + + struct partial_symtab * +-allocate_psymtab (char *filename, struct objfile *objfile) ++allocate_psymtab (const char *filename, struct objfile *objfile) + { + struct partial_symtab *psymtab; + +@@ -3040,7 +3059,8 @@ again2: + + struct partial_symtab * + start_psymtab_common (struct objfile *objfile, +- struct section_offsets *section_offsets, char *filename, ++ struct section_offsets *section_offsets, ++ const char *filename, + CORE_ADDR textlow, struct partial_symbol **global_syms, + struct partial_symbol **static_syms) + { +diff --git a/gdb/symfile.h b/gdb/symfile.h +index 88f8326..50671c1 100644 +--- a/gdb/symfile.h ++++ b/gdb/symfile.h +@@ -140,6 +140,12 @@ struct sym_fns + + void (*sym_read) (struct objfile *, int); + ++ /* Read the partial symbols for an objfile. This may be NULL, in ++ which case gdb assumes that sym_read already read the partial ++ symbols. */ ++ ++ void (*sym_read_psymbols) (struct objfile *); ++ + /* Called when we are finished with an objfile. Should do all + cleanup that is specific to the object file format for the + particular objfile. */ +@@ -250,7 +256,7 @@ extern void free_section_addr_info (struct section_addr_info *); + + extern struct partial_symtab *start_psymtab_common (struct objfile *, + struct section_offsets *, +- char *, CORE_ADDR, ++ const char *, CORE_ADDR, + struct partial_symbol **, + struct partial_symbol **); + +@@ -300,7 +306,7 @@ extern int auto_solib_limit; + + extern void set_initial_language (void); + +-extern struct partial_symtab *allocate_psymtab (char *, struct objfile *); ++extern struct partial_symtab *allocate_psymtab (const char *, struct objfile *); + + extern void discard_psymtab (struct partial_symtab *); + +@@ -369,7 +375,7 @@ void free_symfile_segment_data (struct symfile_segment_data *data); + /* From dwarf2read.c */ + + extern int dwarf2_has_info (struct objfile *); +- ++extern void dwarf2_create_quick_addrmap (struct objfile *); + extern void dwarf2_build_psymtabs (struct objfile *, int); + extern void dwarf2_build_frame_info (struct objfile *); + +diff --git a/gdb/symtab.c b/gdb/symtab.c +index d2ba1f3..593cded 100644 +--- a/gdb/symtab.c ++++ b/gdb/symtab.c +@@ -42,6 +42,7 @@ + #include "ada-lang.h" + #include "p-lang.h" + #include "addrmap.h" ++#include "cp-support.h" + + #include "hashtab.h" + +@@ -55,6 +56,7 @@ + #include "gdb_stat.h" + #include + #include "cp-abi.h" ++#include "cp-support.h" + #include "observer.h" + #include "gdb_assert.h" + #include "solist.h" +@@ -273,7 +275,7 @@ lookup_partial_symtab (const char *name) + make_cleanup (xfree, real_path); + } + +- ALL_PSYMTABS (objfile, pst) ++ ALL_PSYMTABS_REQUIRED (objfile, pst) + { + if (FILENAME_CMP (name, pst->filename) == 0) + { +@@ -870,7 +872,13 @@ find_pc_sect_psymtab (CORE_ADDR pc, struct obj_section *section) + than the later used TEXTLOW/TEXTHIGH one. */ + + ALL_OBJFILES (objfile) +- if (objfile->psymtabs_addrmap != NULL) ++ { ++ if (objfile->quick_addrmap) ++ { ++ if (!addrmap_find (objfile->quick_addrmap, pc)) ++ continue; ++ } ++ if (require_partial_symbols (objfile)->psymtabs_addrmap != NULL) + { + struct partial_symtab *pst; + +@@ -903,6 +911,7 @@ find_pc_sect_psymtab (CORE_ADDR pc, struct obj_section *section) + return pst; + } + } ++ } + + /* Existing PSYMTABS_ADDRMAP mapping is present even for PARTIAL_SYMTABs + which still have no corresponding full SYMTABs read. But it is not +@@ -1170,6 +1179,22 @@ fixup_psymbol_section (struct partial_symbol *psym, struct objfile *objfile) + return psym; + } + ++/* Ensure that the partial symbols for OBJFILE have been loaded. This ++ function always returns its argument, as a convenience. */ ++ ++struct objfile * ++require_partial_symbols (struct objfile *objfile) ++{ ++ if ((objfile->flags & OBJF_SYMTABS_READ) == 0) ++ { ++ objfile->flags |= OBJF_SYMTABS_READ; ++ ++ if (objfile->sf->sym_read_psymbols) ++ (*objfile->sf->sym_read_psymbols) (objfile); ++ } ++ return objfile; ++} ++ + /* Find the definition for a specified symbol name NAME + in domain DOMAIN, visible from lexical block BLOCK. + Returns the struct symbol pointer, or zero if no symbol is found. +@@ -1200,6 +1225,11 @@ lookup_symbol_in_language (const char *name, const struct block *block, + int needtofreename = 0; + struct symbol *returnval; + ++ if(strncmp(name, "::", 2) == 0){/* this must be a global name */ ++ name = name+2; ++ block = NULL; ++ } ++ + modified_name = name; + + /* If we are using C++ or Java, demangle the name before doing a lookup, so +@@ -1213,6 +1243,17 @@ lookup_symbol_in_language (const char *name, const struct block *block, + modified_name = demangled_name; + needtofreename = 1; + } ++ else ++ { ++ /* If we were given a non-mangled name, canonicalize it ++ according to the language (so far only for C++). */ ++ demangled_name = cp_canonicalize_string (name); ++ if (demangled_name) ++ { ++ modified_name = demangled_name; ++ needtofreename = 1; ++ } ++ } + } + else if (lang == language_java) + { +@@ -1361,22 +1402,23 @@ lookup_symbol_aux_local (const char *name, const char *linkage_name, + const domain_enum domain) + { + struct symbol *sym; +- const struct block *static_block = block_static_block (block); ++ const struct block *global_block = block_global_block (block); + + /* Check if either no block is specified or it's a global block. */ + +- if (static_block == NULL) ++ if (global_block == NULL) + return NULL; + +- while (block != static_block) ++ while (block != global_block) + { + sym = lookup_symbol_aux_block (name, linkage_name, block, domain); + if (sym != NULL) + return sym; ++ + block = BLOCK_SUPERBLOCK (block); + } + +- /* We've reached the static block without finding a result. */ ++ /* We've reached the global block without finding a result. */ + + return NULL; + } +@@ -1450,6 +1492,7 @@ lookup_global_symbol_from_objfile (const struct objfile *objfile, + } + + /* Now go through psymtabs. */ ++ require_partial_symbols ((struct objfile *) objfile); + ALL_OBJFILE_PSYMTABS (objfile, ps) + { + if (!ps->readin +@@ -1520,7 +1563,7 @@ lookup_symbol_aux_psymtabs (int block_index, const char *name, + struct symtab *s; + const int psymtab_index = (block_index == GLOBAL_BLOCK ? 1 : 0); + +- ALL_PSYMTABS (objfile, ps) ++ ALL_PSYMTABS_REQUIRED (objfile, ps) + { + if (!ps->readin + && lookup_partial_symbol (ps, name, linkage_name, +@@ -1805,7 +1848,11 @@ basic_lookup_transparent_type (const char *name) + } + } + +- ALL_PSYMTABS (objfile, ps) ++ /* FIXME: .debug_pubnames should be read in. ++ ++ One may also try to the first pass without the require_partial_symbols ++ call but that would behave nondeterministically. */ ++ ALL_PSYMTABS_REQUIRED (objfile, ps) + { + if (!ps->readin && lookup_partial_symbol (ps, name, NULL, + 1, STRUCT_DOMAIN)) +@@ -1853,7 +1900,12 @@ basic_lookup_transparent_type (const char *name) + } + } + +- ALL_PSYMTABS (objfile, ps) ++ /* FIXME: Something like .debug_pubnames containing also static symbols ++ should be read in. Compiler needs to be taught to generate it first. ++ ++ One may also try to the first pass without the require_partial_symbols ++ call but that would behave nondeterministically. */ ++ ALL_PSYMTABS_REQUIRED (objfile, ps) + { + if (!ps->readin && lookup_partial_symbol (ps, name, NULL, 0, STRUCT_DOMAIN)) + { +@@ -1894,7 +1946,21 @@ find_main_psymtab (void) + struct partial_symtab *pst; + struct objfile *objfile; + +- ALL_PSYMTABS (objfile, pst) ++ ALL_OBJFILES (objfile) ++ { ++ if ((objfile->flags & OBJF_MAIN) == 0) ++ continue; ++ require_partial_symbols (objfile); ++ ALL_OBJFILE_PSYMTABS (objfile, pst) ++ { ++ if (lookup_partial_symbol (pst, main_name (), NULL, 1, VAR_DOMAIN)) ++ { ++ return pst; ++ } ++ } ++ } ++ ++ ALL_PSYMTABS_REQUIRED (objfile, pst) + { + if (lookup_partial_symbol (pst, main_name (), NULL, 1, VAR_DOMAIN)) + { +@@ -3085,7 +3151,7 @@ search_symbols (char *regexp, domain_enum kind, int nfiles, char *files[], + matching the regexp. That way we don't have to reproduce all of + the machinery below. */ + +- ALL_PSYMTABS (objfile, ps) ++ ALL_PSYMTABS_REQUIRED (objfile, ps) + { + struct partial_symbol **bound, **gbound, **sbound; + int keep_going = 1; +diff --git a/gdb/symtab.h b/gdb/symtab.h +index 8b086f3..06bf7e8 100644 +--- a/gdb/symtab.h ++++ b/gdb/symtab.h +@@ -171,9 +171,6 @@ extern CORE_ADDR symbol_overlayed_address (CORE_ADDR, struct obj_section *); + #define SYMBOL_SECTION(symbol) (symbol)->ginfo.section + #define SYMBOL_OBJ_SECTION(symbol) (symbol)->ginfo.obj_section + +-#define SYMBOL_CPLUS_DEMANGLED_NAME(symbol) \ +- (symbol)->ginfo.language_specific.cplus_specific.demangled_name +- + /* Initializes the language dependent portion of a symbol + depending upon the language for the symbol. */ + #define SYMBOL_INIT_LANGUAGE_SPECIFIC(symbol,language) \ +@@ -394,7 +391,10 @@ typedef enum domain_enum_tag + FUNCTIONS_DOMAIN, + + /* All defined types */ +- TYPES_DOMAIN ++ TYPES_DOMAIN, ++ ++ /* Fortran common blocks. Their naming must be separate from VAR_DOMAIN. */ ++ COMMON_BLOCK_DOMAIN + } + domain_enum; + +@@ -1027,6 +1027,8 @@ extern void clear_pc_function_cache (void); + + /* from symtab.c: */ + ++struct objfile *require_partial_symbols (struct objfile *); ++ + /* lookup partial symbol table by filename */ + + extern struct partial_symtab *lookup_partial_symtab (const char *); +diff --git a/gdb/syscalls/gdb-syscalls.dtd b/gdb/syscalls/gdb-syscalls.dtd +new file mode 100644 +index 0000000..0d40ab4 +--- /dev/null ++++ b/gdb/syscalls/gdb-syscalls.dtd +@@ -0,0 +1,21 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/gdb/syscalls/i386-linux.xml b/gdb/syscalls/i386-linux.xml +new file mode 100644 +index 0000000..6f2beee +--- /dev/null ++++ b/gdb/syscalls/i386-linux.xml +@@ -0,0 +1,334 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/gdb/syscalls/ppc-linux.xml b/gdb/syscalls/ppc-linux.xml +new file mode 100644 +index 0000000..f09fabd +--- /dev/null ++++ b/gdb/syscalls/ppc-linux.xml +@@ -0,0 +1,304 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/gdb/syscalls/ppc64-linux.xml b/gdb/syscalls/ppc64-linux.xml +new file mode 100644 +index 0000000..7ee929c +--- /dev/null ++++ b/gdb/syscalls/ppc64-linux.xml +@@ -0,0 +1,289 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/gdb/target.c b/gdb/target.c +index b89d551..831070c 100644 +--- a/gdb/target.c ++++ b/gdb/target.c +@@ -443,6 +443,8 @@ update_current_target (void) + /* Do not inherit to_follow_fork. */ + INHERIT (to_insert_exec_catchpoint, t); + INHERIT (to_remove_exec_catchpoint, t); ++ INHERIT (to_passed_by_entrypoint, t); ++ INHERIT (to_set_syscall_catchpoint, t); + INHERIT (to_has_exited, t); + /* Do not inherit to_mourn_inferiour. */ + INHERIT (to_can_run, t); +@@ -586,9 +588,15 @@ update_current_target (void) + de_fault (to_insert_exec_catchpoint, + (void (*) (int)) + tcomplain); ++ de_fault (to_passed_by_entrypoint, ++ (int (*) (void)) ++ tcomplain); + de_fault (to_remove_exec_catchpoint, + (int (*) (int)) + tcomplain); ++ de_fault (to_set_syscall_catchpoint, ++ (int (*) (int, int, int, int, int *)) ++ tcomplain); + de_fault (to_has_exited, + (int (*) (int, int, int *)) + return_zero); +@@ -2677,9 +2685,9 @@ target_waitstatus_to_string (const struct target_waitstatus *ws) + case TARGET_WAITKIND_EXECD: + return xstrprintf ("%sexecd", kind_str); + case TARGET_WAITKIND_SYSCALL_ENTRY: +- return xstrprintf ("%ssyscall-entry", kind_str); ++ return xstrprintf ("%sentered syscall", kind_str); + case TARGET_WAITKIND_SYSCALL_RETURN: +- return xstrprintf ("%ssyscall-return", kind_str); ++ return xstrprintf ("%sexited syscall", kind_str); + case TARGET_WAITKIND_SPURIOUS: + return xstrprintf ("%sspurious", kind_str); + case TARGET_WAITKIND_IGNORE: +diff --git a/gdb/target.h b/gdb/target.h +index 7f4cd8f..8dcc3d6 100644 +--- a/gdb/target.h ++++ b/gdb/target.h +@@ -140,18 +140,34 @@ struct target_waitstatus + { + enum target_waitkind kind; + +- /* Forked child pid, execd pathname, exit status or signal number. */ ++ /* Forked child pid, execd pathname, exit status, signal number or ++ syscall name. */ + union + { + int integer; + enum target_signal sig; + ptid_t related_pid; + char *execd_pathname; +- int syscall_id; ++ int syscall_number; + } + value; + }; + ++/* The structure below stores information about a system call. ++ It is basically used in the "catch syscall" command, and in ++ every function that gives information about a system call. ++ ++ It's also good to mention that its fields represent everything ++ that we currently know about a syscall in GDB. */ ++struct syscall ++ { ++ /* The syscall number. */ ++ int number; ++ ++ /* The syscall name. */ ++ const char *name; ++ }; ++ + /* Return a pretty printed form of target_waitstatus. + Space for the result is malloc'd, caller must free. */ + extern char *target_waitstatus_to_string (const struct target_waitstatus *); +@@ -392,6 +408,8 @@ struct target_ops + int (*to_follow_fork) (struct target_ops *, int); + void (*to_insert_exec_catchpoint) (int); + int (*to_remove_exec_catchpoint) (int); ++ int (*to_passed_by_entrypoint) (void); ++ int (*to_set_syscall_catchpoint) (int, int, int, int, int *); + int (*to_has_exited) (int, int, int *); + void (*to_mourn_inferior) (struct target_ops *); + int (*to_can_run) (void); +@@ -723,6 +741,8 @@ extern int inferior_has_vforked (ptid_t pid, ptid_t *child_pid); + + extern int inferior_has_execd (ptid_t pid, char **execd_pathname); + ++extern int inferior_has_called_syscall (ptid_t pid, int *syscall_number); ++ + /* From exec.c */ + + extern void print_section_info (struct target_ops *, bfd *); +@@ -881,6 +901,21 @@ int target_follow_fork (int follow_child); + #define target_remove_exec_catchpoint(pid) \ + (*current_target.to_remove_exec_catchpoint) (pid) + ++/* Has the inferior already passed through its entrypoint? */ ++#define target_passed_by_entrypoint() \ ++ (*current_target.to_passed_by_entrypoint) () ++ ++/* Syscall catch. NEEDED is nonzero if any syscall catch (of any ++ kind) is requested. ANY_COUNT is nonzero if a generic ++ (filter-less) syscall catch is being requested. TABLE is an array ++ of ints, indexed by syscall number. An element in this array is ++ nonzero if that syscall should be caught. TABLE_SIZE is the number ++ of elements in TABLE. */ ++ ++#define target_set_syscall_catchpoint(pid, needed, any_count, table_size, table) \ ++ (*current_target.to_set_syscall_catchpoint) (pid, needed, any_count, \ ++ table_size, table) ++ + /* Returns TRUE if PID has exited. And, also sets EXIT_STATUS to the + exit code of PID, if any. */ + +@@ -1146,6 +1181,20 @@ extern int target_search_memory (CORE_ADDR start_addr, + ULONGEST pattern_len, + CORE_ADDR *found_addrp); + ++/* Utility functions which can be used by search_memory implementations. */ ++ ++void allocate_pattern_buffer (char **pattern_bufp, char **pattern_buf_end, ++ ULONGEST *pattern_buf_size); ++ ++void increase_pattern_buffer (char **pattern_bufp, char **pattern_buf_end, ++ ULONGEST *pattern_buf_size, int val_bytes); ++ ++int search_memory (CORE_ADDR *start_addr, ULONGEST *search_space_len, ++ const char *pattern_buf, ULONGEST pattern_len, ++ CORE_ADDR *found_addr); ++ ++void put_bits (bfd_uint64_t data, char *buf, int bits, bfd_boolean big_p); ++ + /* Command logging facility. */ + + #define target_log_command(p) \ +diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog +index e3aaeab..e886869 100644 +--- a/gdb/testsuite/ChangeLog ++++ b/gdb/testsuite/ChangeLog +@@ -1,3 +1,7 @@ ++2009-03-05 Pedro Alves ++ ++ * gdb.arch/i386-permbkpt.S, gdb.arch/i386-permbkpt.exp: New. ++ + 2009-02-18 Jan Kratochvil + + * gdb.base/macscp.exp (objfile): Move it to ${objdir}/${subdir}/. +diff --git a/gdb/testsuite/configure.ac b/gdb/testsuite/configure.ac +index 3d8fae4..5fb9067 100644 +--- a/gdb/testsuite/configure.ac ++++ b/gdb/testsuite/configure.ac +@@ -1,7 +1,7 @@ + # -*- Autoconf -*- + # Process this file with autoconf to produce a configure script. + +-# Copyright 2002, 2003, 2004, 2005 ++# Copyright 2002, 2003, 2004, 2005, 2008 + # Free Software Foundation, Inc. + # + # This program is free software; you can redistribute it and/or modify +diff --git a/gdb/testsuite/gdb.arch/i386-permbkpt.S b/gdb/testsuite/gdb.arch/i386-permbkpt.S +new file mode 100644 +index 0000000..02a31d6 +--- /dev/null ++++ b/gdb/testsuite/gdb.arch/i386-permbkpt.S +@@ -0,0 +1,30 @@ ++/* Copyright 2009 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++ This file is part of the gdb testsuite. */ ++ ++#define CONCAT1(a, b) CONCAT2(a, b) ++#define CONCAT2(a, b) a ## b ++ ++#ifdef SYMBOL_PREFIX ++# define SYMBOL(str) CONCAT1(SYMBOL_PREFIX, str) ++#else ++# define SYMBOL(str) str ++#endif ++ ++ .global SYMBOL(main) ++SYMBOL(main): ++ int3 ++ ret +diff --git a/gdb/testsuite/gdb.arch/i386-permbkpt.exp b/gdb/testsuite/gdb.arch/i386-permbkpt.exp +new file mode 100644 +index 0000000..f1930e5 +--- /dev/null ++++ b/gdb/testsuite/gdb.arch/i386-permbkpt.exp +@@ -0,0 +1,52 @@ ++# Copyright (C) 2009 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++ ++# This file is part of the gdb testsuite. ++ ++if $tracelevel { ++ strace $tracelevel ++} ++ ++# Test inserting breakpoints over permanent breakpoints on i386 and amd64. ++ ++if { ![istarget "i?86-*-*"] && ![istarget "x86_64-*-*"] } then { ++ verbose "Skipping i386 test for multi break at permanent breakpoint location." ++ return ++} ++ ++set testfile "i386-permbkpt" ++set srcfile ${testfile}.S ++set binfile ${objdir}/${subdir}/${testfile} ++ ++# Some targets have leading underscores on assembly symbols. ++# TODO: detect this automatically ++set additional_flags "" ++if { [istarget "*-*-cygwin*"] || [istarget "*-*-mingw*"] } then { ++ set additional_flags "additional_flags=-DSYMBOL_PREFIX=_" ++} ++ ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable [list debug $additional_flags]] != "" } { ++ untested i386-permbkpt.exp ++ return -1 ++} ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++gdb_test "break main" "" "First permanent break" ++gdb_test "break main" "" "Second permanent break" +diff --git a/gdb/testsuite/gdb.arch/powerpc-power7.exp b/gdb/testsuite/gdb.arch/powerpc-power7.exp +new file mode 100644 +index 0000000..d9c48f9 +--- /dev/null ++++ b/gdb/testsuite/gdb.arch/powerpc-power7.exp +@@ -0,0 +1,166 @@ ++# Copyright 2009 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++# Test PowerPC Power7 instructions disassembly. ++ ++if {![istarget "powerpc*-*-*"]} then { ++ verbose "Skipping PowerPC Power7 instructions disassembly." ++ return ++} ++ ++set testfile "powerpc-power7" ++set srcfile ${testfile}.s ++set objfile ${objdir}/${subdir}/${testfile}.o ++ ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${objfile}" object {debug}] != "" } { ++ untested "PowerPC Power7 instructions disassembly" ++ return -1 ++} ++ ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${objfile} ++ ++ ++# Disassemble the function. ++ ++set test "disass func" ++gdb_test_multiple $test $test { ++ -re "\r\nDump of assembler code for function func:(\r\n.*\r\n)End of assembler dump.\r\n$gdb_prompt $" { ++ set func $expect_out(1,string) ++ pass $test ++ } ++} ++ ++proc func_check {offset instr} { ++ global func ++ ++ # 0x0000000000000018 : stxvd2x vs43,r4,r5 ++ set patt ".*\r\n[string map {0x 0x0*} $offset] :\[ \t\]*[string map [list { } "\[ \t\]+" . {\.}] $instr]\[ \t\]*\r\n.*" ++ set test "Found $offset: $instr" ++ if [regexp -nocase -line $patt $func] { ++ pass $test ++ } else { ++ fail $test ++ } ++} ++ ++func_check 0x0 "lxvd2x vs3,r4,r5" ++func_check 0x4 "lxvd2ux vs3,r4,r5" ++func_check 0x8 "lxvd2x vs43,r4,r5" ++func_check 0xc "lxvd2ux vs43,r4,r5" ++func_check 0x10 "stxvd2x vs3,r4,r5" ++func_check 0x14 "stxvd2ux vs3,r4,r5" ++func_check 0x18 "stxvd2x vs43,r4,r5" ++func_check 0x1c "stxvd2ux vs43,r4,r5" ++func_check 0x20 "xxmrghd vs3,vs4,vs5" ++func_check 0x24 "xxmrghd vs43,vs44,vs45" ++func_check 0x28 "xxmrgld vs3,vs4,vs5" ++func_check 0x2c "xxmrgld vs43,vs44,vs45" ++func_check 0x30 "xxmrghd vs3,vs4,vs5" ++func_check 0x34 "xxmrghd vs43,vs44,vs45" ++func_check 0x38 "xxmrgld vs3,vs4,vs5" ++func_check 0x3c "xxmrgld vs43,vs44,vs45" ++func_check 0x40 "xxpermdi vs3,vs4,vs5,1" ++func_check 0x44 "xxpermdi vs43,vs44,vs45,1" ++func_check 0x48 "xxpermdi vs3,vs4,vs5,2" ++func_check 0x4c "xxpermdi vs43,vs44,vs45,2" ++func_check 0x50 "xvmovdp vs3,vs4" ++func_check 0x54 "xvmovdp vs43,vs44" ++func_check 0x58 "xvmovdp vs3,vs4" ++func_check 0x5c "xvmovdp vs43,vs44" ++func_check 0x60 "xvcpsgndp vs3,vs4,vs5" ++func_check 0x64 "xvcpsgndp vs43,vs44,vs45" ++func_check 0x68 "wait" ++func_check 0x6c "wait" ++func_check 0x70 "waitrsv" ++func_check 0x74 "waitrsv" ++func_check 0x78 "waitimpl" ++func_check 0x7c "waitimpl" ++func_check 0x80 "doze" ++func_check 0x84 "nap" ++func_check 0x88 "sleep" ++func_check 0x8c "rvwinkle" ++func_check 0x90 "prtyw r3,r4" ++func_check 0x94 "prtyd r13,r14" ++func_check 0x98 "mfcfar r10" ++func_check 0x9c "mtcfar r11" ++func_check 0xa0 "cmpb r3,r4,r5" ++func_check 0xa4 "lwzcix r10,r11,r12" ++func_check 0xa8 "dadd f16,f17,f18" ++func_check 0xac "daddq f20,f22,f24" ++func_check 0xb0 "dss 3" ++func_check 0xb4 "dssall" ++func_check 0xb8 "dst r5,r4,1" ++func_check 0xbc "dstt r8,r7,0" ++func_check 0xc0 "dstst r5,r6,3" ++func_check 0xc4 "dststt r4,r5,2" ++func_check 0xc8 "divwe r10,r11,r12" ++func_check 0xcc "divwe. r11,r12,r13" ++func_check 0xd0 "divweo r12,r13,r14" ++func_check 0xd4 "divweo. r13,r14,r15" ++func_check 0xd8 "divweu r10,r11,r12" ++func_check 0xdc "divweu. r11,r12,r13" ++func_check 0xe0 "divweuo r12,r13,r14" ++func_check 0xe4 "divweuo. r13,r14,r15" ++func_check 0xe8 "bpermd r7,r17,r27" ++func_check 0xec "popcntw r10,r20" ++func_check 0xf0 "popcntd r10,r20" ++func_check 0xf4 "ldbrx r20,r21,r22" ++func_check 0xf8 "stdbrx r20,r21,r22" ++func_check 0xfc "lfiwzx f10,0,r10" ++func_check 0x100 "lfiwzx f10,r9,r10" ++func_check 0x104 "fcfids f4,f5" ++func_check 0x108 "fcfids. f4,f5" ++func_check 0x10c "fcfidus f4,f5" ++func_check 0x110 "fcfidus. f4,f5" ++func_check 0x114 "fctiwu f4,f5" ++func_check 0x118 "fctiwu. f4,f5" ++func_check 0x11c "fctiwuz f4,f5" ++func_check 0x120 "fctiwuz. f4,f5" ++func_check 0x124 "fctidu f4,f5" ++func_check 0x128 "fctidu. f4,f5" ++func_check 0x12c "fctiduz f4,f5" ++func_check 0x130 "fctiduz. f4,f5" ++func_check 0x134 "fcfidu f4,f5" ++func_check 0x138 "fcfidu. f4,f5" ++func_check 0x13c "ftdiv cr0,f10,f11" ++func_check 0x140 "ftdiv cr7,f10,f11" ++func_check 0x144 "ftsqrt cr0,f10" ++func_check 0x148 "ftsqrt cr7,f10" ++func_check 0x14c "dcbtt r8,r9" ++func_check 0x150 "dcbtstt r8,r9" ++func_check 0x154 "dcffix f10,f12" ++func_check 0x158 "dcffix. f20,f22" ++func_check 0x15c "lbarx r10,r11,r12" ++func_check 0x160 "lbarx r10,r11,r12" ++func_check 0x164 "lbarx r10,r11,r12,1" ++func_check 0x168 "lharx r20,r21,r22" ++func_check 0x16c "lharx r20,r21,r22" ++func_check 0x170 "lharx r20,r21,r22,1" ++func_check 0x174 "stbcx. r10,r11,r12" ++func_check 0x178 "sthcx. r10,r11,r12" ++func_check 0x17c "fre f14,f15" ++func_check 0x180 "fre. f14,f15" ++func_check 0x184 "fres f14,f15" ++func_check 0x188 "fres. f14,f15" ++func_check 0x18c "frsqrte f14,f15" ++func_check 0x190 "frsqrte. f14,f15" ++func_check 0x194 "frsqrtes f14,f15" ++func_check 0x198 "frsqrtes. f14,f15" ++func_check 0x19c "isel r2,r3,r4,28" +diff --git a/gdb/testsuite/gdb.arch/powerpc-power7.s b/gdb/testsuite/gdb.arch/powerpc-power7.s +new file mode 100644 +index 0000000..98b2e79 +--- /dev/null ++++ b/gdb/testsuite/gdb.arch/powerpc-power7.s +@@ -0,0 +1,107 @@ ++ .text ++ .globl func ++func: ++ .long 0x7c642e98 /* 0: lxvd2x vs3,r4,r5 */ ++ .long 0x7c642ed8 /* 4: lxvd2ux vs3,r4,r5 */ ++ .long 0x7d642e99 /* 8: lxvd2x vs43,r4,r5 */ ++ .long 0x7d642ed9 /* c: lxvd2ux vs43,r4,r5 */ ++ .long 0x7c642f98 /* 10: stxvd2x vs3,r4,r5 */ ++ .long 0x7c642fd8 /* 14: stxvd2ux vs3,r4,r5 */ ++ .long 0x7d642f99 /* 18: stxvd2x vs43,r4,r5 */ ++ .long 0x7d642fd9 /* 1c: stxvd2ux vs43,r4,r5 */ ++ .long 0xf0642850 /* 20: xxmrghd vs3,vs4,vs5 */ ++ .long 0xf16c6857 /* 24: xxmrghd vs43,vs44,vs45 */ ++ .long 0xf0642b50 /* 28: xxmrgld vs3,vs4,vs5 */ ++ .long 0xf16c6b57 /* 2c: xxmrgld vs43,vs44,vs45 */ ++ .long 0xf0642850 /* 30: xxmrghd vs3,vs4,vs5 */ ++ .long 0xf16c6857 /* 34: xxmrghd vs43,vs44,vs45 */ ++ .long 0xf0642b50 /* 38: xxmrgld vs3,vs4,vs5 */ ++ .long 0xf16c6b57 /* 3c: xxmrgld vs43,vs44,vs45 */ ++ .long 0xf0642950 /* 40: xxpermdi vs3,vs4,vs5,1 */ ++ .long 0xf16c6957 /* 44: xxpermdi vs43,vs44,vs45,1 */ ++ .long 0xf0642a50 /* 48: xxpermdi vs3,vs4,vs5,2 */ ++ .long 0xf16c6a57 /* 4c: xxpermdi vs43,vs44,vs45,2 */ ++ .long 0xf0642780 /* 50: xvmovdp vs3,vs4 */ ++ .long 0xf16c6787 /* 54: xvmovdp vs43,vs44 */ ++ .long 0xf0642780 /* 58: xvmovdp vs3,vs4 */ ++ .long 0xf16c6787 /* 5c: xvmovdp vs43,vs44 */ ++ .long 0xf0642f80 /* 60: xvcpsgndp vs3,vs4,vs5 */ ++ .long 0xf16c6f87 /* 64: xvcpsgndp vs43,vs44,vs45 */ ++ .long 0x7c00007c /* 68: wait */ ++ .long 0x7c00007c /* 6c: wait */ ++ .long 0x7c20007c /* 70: waitrsv */ ++ .long 0x7c20007c /* 74: waitrsv */ ++ .long 0x7c40007c /* 78: waitimpl */ ++ .long 0x7c40007c /* 7c: waitimpl */ ++ .long 0x4c000324 /* 80: doze */ ++ .long 0x4c000364 /* 84: nap */ ++ .long 0x4c0003a4 /* 88: sleep */ ++ .long 0x4c0003e4 /* 8c: rvwinkle */ ++ .long 0x7c830134 /* 90: prtyw r3,r4 */ ++ .long 0x7dcd0174 /* 94: prtyd r13,r14 */ ++ .long 0x7d5c02a6 /* 98: mfcfar r10 */ ++ .long 0x7d7c03a6 /* 9c: mtcfar r11 */ ++ .long 0x7c832bf8 /* a0: cmpb r3,r4,r5 */ ++ .long 0x7d4b662a /* a4: lwzcix r10,r11,r12 */ ++ .long 0xee119004 /* a8: dadd f16,f17,f18 */ ++ .long 0xfe96c004 /* ac: daddq f20,f22,f24 */ ++ .long 0x7c60066c /* b0: dss 3 */ ++ .long 0x7e00066c /* b4: dssall */ ++ .long 0x7c2522ac /* b8: dst r5,r4,1 */ ++ .long 0x7e083aac /* bc: dstt r8,r7,0 */ ++ .long 0x7c6532ec /* c0: dstst r5,r6,3 */ ++ .long 0x7e442aec /* c4: dststt r4,r5,2 */ ++ .long 0x7d4b6356 /* c8: divwe r10,r11,r12 */ ++ .long 0x7d6c6b57 /* cc: divwe. r11,r12,r13 */ ++ .long 0x7d8d7756 /* d0: divweo r12,r13,r14 */ ++ .long 0x7dae7f57 /* d4: divweo. r13,r14,r15 */ ++ .long 0x7d4b6316 /* d8: divweu r10,r11,r12 */ ++ .long 0x7d6c6b17 /* dc: divweu. r11,r12,r13 */ ++ .long 0x7d8d7716 /* e0: divweuo r12,r13,r14 */ ++ .long 0x7dae7f17 /* e4: divweuo. r13,r14,r15 */ ++ .long 0x7e27d9f8 /* e8: bpermd r7,r17,r27 */ ++ .long 0x7e8a02f4 /* ec: popcntw r10,r20 */ ++ .long 0x7e8a03f4 /* f0: popcntd r10,r20 */ ++ .long 0x7e95b428 /* f4: ldbrx r20,r21,r22 */ ++ .long 0x7e95b528 /* f8: stdbrx r20,r21,r22 */ ++ .long 0x7d4056ee /* fc: lfiwzx f10,0,r10 */ ++ .long 0x7d4956ee /* 100: lfiwzx f10,r9,r10 */ ++ .long 0xec802e9c /* 104: fcfids f4,f5 */ ++ .long 0xec802e9d /* 108: fcfids. f4,f5 */ ++ .long 0xec802f9c /* 10c: fcfidus f4,f5 */ ++ .long 0xec802f9d /* 110: fcfidus. f4,f5 */ ++ .long 0xfc80291c /* 114: fctiwu f4,f5 */ ++ .long 0xfc80291d /* 118: fctiwu. f4,f5 */ ++ .long 0xfc80291e /* 11c: fctiwuz f4,f5 */ ++ .long 0xfc80291f /* 120: fctiwuz. f4,f5 */ ++ .long 0xfc802f5c /* 124: fctidu f4,f5 */ ++ .long 0xfc802f5d /* 128: fctidu. f4,f5 */ ++ .long 0xfc802f5e /* 12c: fctiduz f4,f5 */ ++ .long 0xfc802f5f /* 130: fctiduz. f4,f5 */ ++ .long 0xfc802f9c /* 134: fcfidu f4,f5 */ ++ .long 0xfc802f9d /* 138: fcfidu. f4,f5 */ ++ .long 0xfc0a5900 /* 13c: ftdiv cr0,f10,f11 */ ++ .long 0xff8a5900 /* 140: ftdiv cr7,f10,f11 */ ++ .long 0xfc005140 /* 144: ftsqrt cr0,f10 */ ++ .long 0xff805140 /* 148: ftsqrt cr7,f10 */ ++ .long 0x7e084a2c /* 14c: dcbtt r8,r9 */ ++ .long 0x7e0849ec /* 150: dcbtstt r8,r9 */ ++ .long 0xed406644 /* 154: dcffix f10,f12 */ ++ .long 0xee80b645 /* 158: dcffix. f20,f22 */ ++ .long 0x7d4b6068 /* 15c: lbarx r10,r11,r12 */ ++ .long 0x7d4b6068 /* 160: lbarx r10,r11,r12 */ ++ .long 0x7d4b6069 /* 164: lbarx r10,r11,r12,1 */ ++ .long 0x7e95b0e8 /* 168: lharx r20,r21,r22 */ ++ .long 0x7e95b0e8 /* 16c: lharx r20,r21,r22 */ ++ .long 0x7e95b0e9 /* 170: lharx r20,r21,r22,1 */ ++ .long 0x7d4b656d /* 174: stbcx. r10,r11,r12 */ ++ .long 0x7d4b65ad /* 178: sthcx. r10,r11,r12 */ ++ .long 0xfdc07830 /* 17c: fre f14,f15 */ ++ .long 0xfdc07831 /* 180: fre. f14,f15 */ ++ .long 0xedc07830 /* 184: fres f14,f15 */ ++ .long 0xedc07831 /* 188: fres. f14,f15 */ ++ .long 0xfdc07834 /* 18c: frsqrte f14,f15 */ ++ .long 0xfdc07835 /* 190: frsqrte. f14,f15 */ ++ .long 0xedc07834 /* 194: frsqrtes f14,f15 */ ++ .long 0xedc07835 /* 198: frsqrtes. f14,f15 */ ++ .long 0x7c43271e /* 19c: isel r2,r3,r4,28 */ +diff --git a/gdb/testsuite/gdb.arch/x86_64-vla-typedef-foo.S b/gdb/testsuite/gdb.arch/x86_64-vla-typedef-foo.S +new file mode 100644 +index 0000000..66f7a39 +--- /dev/null ++++ b/gdb/testsuite/gdb.arch/x86_64-vla-typedef-foo.S +@@ -0,0 +1,455 @@ ++ .file "x86_64-vla-typedef.c" ++ .section .debug_abbrev,"",@progbits ++.Ldebug_abbrev0: ++ .section .debug_info,"",@progbits ++.Ldebug_info0: ++ .section .debug_line,"",@progbits ++.Ldebug_line0: ++ .text ++.Ltext0: ++.globl foo ++ .type foo, @function ++foo: ++.LFB2: ++ .file 1 "x86_64-vla-typedef.c" ++ .loc 1 22 0 ++ pushq %rbp ++.LCFI0: ++ movq %rsp, %rbp ++.LCFI1: ++ subq $64, %rsp ++.LCFI2: ++ movl %edi, -36(%rbp) ++ .loc 1 22 0 ++ movq %rsp, %rax ++ movq %rax, -48(%rbp) ++ .loc 1 23 0 ++ movl -36(%rbp), %edx ++ movslq %edx,%rax ++ subq $1, %rax ++ movq %rax, -24(%rbp) ++ .loc 1 24 0 ++ movslq %edx,%rax ++ addq $15, %rax ++ addq $15, %rax ++ shrq $4, %rax ++ salq $4, %rax ++ subq %rax, %rsp ++ movq %rsp, -56(%rbp) ++ movq -56(%rbp), %rax ++ addq $15, %rax ++ shrq $4, %rax ++ salq $4, %rax ++ movq %rax, -56(%rbp) ++ movq -56(%rbp), %rax ++ movq %rax, -16(%rbp) ++ .loc 1 27 0 ++ movl $0, -4(%rbp) ++ jmp .L2 ++.L3: ++ .loc 1 28 0 ++ movl -4(%rbp), %esi ++ movl -4(%rbp), %eax ++ movl %eax, %ecx ++ movq -16(%rbp), %rdx ++ movslq %esi,%rax ++ movb %cl, (%rdx,%rax) ++ .loc 1 27 0 ++ addl $1, -4(%rbp) ++.L2: ++ movl -4(%rbp), %eax ++ cmpl -36(%rbp), %eax ++ jl .L3 ++ .loc 1 30 0 ++ .globl break_here ++break_here: ++ movq -16(%rbp), %rax ++ movb $0, (%rax) ++ movq -48(%rbp), %rsp ++ .loc 1 31 0 ++ leave ++ ret ++.LFE2: ++ .size foo, .-foo ++ .section .debug_frame,"",@progbits ++.Lframe0: ++ .long .LECIE0-.LSCIE0 ++.LSCIE0: ++ .long 0xffffffff ++ .byte 0x1 ++ .string "" ++ .uleb128 0x1 ++ .sleb128 -8 ++ .byte 0x10 ++ .byte 0xc ++ .uleb128 0x7 ++ .uleb128 0x8 ++ .byte 0x90 ++ .uleb128 0x1 ++ .align 8 ++.LECIE0: ++.LSFDE0: ++ .long .LEFDE0-.LASFDE0 ++.LASFDE0: ++ .long .Lframe0 ++ .quad .LFB2 ++ .quad .LFE2-.LFB2 ++ .byte 0x4 ++ .long .LCFI0-.LFB2 ++ .byte 0xe ++ .uleb128 0x10 ++ .byte 0x86 ++ .uleb128 0x2 ++ .byte 0x4 ++ .long .LCFI1-.LCFI0 ++ .byte 0xd ++ .uleb128 0x6 ++ .align 8 ++.LEFDE0: ++ .section .eh_frame,"a",@progbits ++.Lframe1: ++ .long .LECIE1-.LSCIE1 ++.LSCIE1: ++ .long 0x0 ++ .byte 0x1 ++ .string "zR" ++ .uleb128 0x1 ++ .sleb128 -8 ++ .byte 0x10 ++ .uleb128 0x1 ++ .byte 0x3 ++ .byte 0xc ++ .uleb128 0x7 ++ .uleb128 0x8 ++ .byte 0x90 ++ .uleb128 0x1 ++ .align 8 ++.LECIE1: ++.LSFDE1: ++ .long .LEFDE1-.LASFDE1 ++.LASFDE1: ++ .long .LASFDE1-.Lframe1 ++ .long .LFB2 ++ .long .LFE2-.LFB2 ++ .uleb128 0x0 ++ .byte 0x4 ++ .long .LCFI0-.LFB2 ++ .byte 0xe ++ .uleb128 0x10 ++ .byte 0x86 ++ .uleb128 0x2 ++ .byte 0x4 ++ .long .LCFI1-.LCFI0 ++ .byte 0xd ++ .uleb128 0x6 ++ .align 8 ++.LEFDE1: ++ .text ++.Letext0: ++ .section .debug_loc,"",@progbits ++.Ldebug_loc0: ++.LLST0: ++ .quad .LFB2-.Ltext0 ++ .quad .LCFI0-.Ltext0 ++ .value 0x2 ++ .byte 0x77 ++ .sleb128 8 ++ .quad .LCFI0-.Ltext0 ++ .quad .LCFI1-.Ltext0 ++ .value 0x2 ++ .byte 0x77 ++ .sleb128 16 ++ .quad .LCFI1-.Ltext0 ++ .quad .LFE2-.Ltext0 ++ .value 0x2 ++ .byte 0x76 ++ .sleb128 16 ++ .quad 0x0 ++ .quad 0x0 ++ .section .debug_info ++ .long .Ldebug_end - .Ldebug_start ++.Ldebug_start: ++ .value 0x2 ++ .long .Ldebug_abbrev0 ++ .byte 0x8 ++ .uleb128 0x1 ++ .long .LASF2 ++ .byte 0x1 ++ .long .LASF3 ++ .long .LASF4 ++ .quad .Ltext0 ++ .quad .Letext0 ++ .long .Ldebug_line0 ++ .uleb128 0x2 ++ .byte 0x1 ++ .string "foo" ++ .byte 0x1 ++ .byte 0x16 ++ .byte 0x1 ++ .quad .LFB2 ++ .quad .LFE2 ++ .long .LLST0 ++ .long 0x83 ++ .uleb128 0x3 ++ .long .LASF5 ++ .byte 0x1 ++ .byte 0x15 ++ .long 0x83 ++ .byte 0x2 ++ .byte 0x91 ++ .sleb128 -52 ++.Ltag_typedef: ++ .uleb128 0x4 ++ .long .LASF6 ++ .byte 0x1 ++ .byte 0x17 ++ .long .Ltag_array_type - .debug_info ++ .uleb128 0x5 /* Abbrev Number: 5 (DW_TAG_variable) */ ++ .long .LASF0 ++ .byte 0x1 ++ .byte 0x18 ++#if 1 ++ .long .Ltag_typedef - .debug_info ++#else ++ /* Debugging only: Skip the typedef indirection. */ ++ .long .Ltag_array_type - .debug_info ++#endif ++ /* DW_AT_location: DW_FORM_block1: start */ ++ .byte 0x3 ++ .byte 0x91 ++ .sleb128 -32 ++#if 0 ++ .byte 0x6 /* DW_OP_deref */ ++#else ++ .byte 0x96 /* DW_OP_nop */ ++#endif ++ /* DW_AT_location: DW_FORM_block1: end */ ++ .uleb128 0x6 ++ .string "i" ++ .byte 0x1 ++ .byte 0x19 ++ .long 0x83 ++ .byte 0x2 ++ .byte 0x91 ++ .sleb128 -20 ++ .byte 0x0 ++ .uleb128 0x7 ++ .byte 0x4 ++ .byte 0x5 ++ .string "int" ++.Ltag_array_type: ++ .uleb128 0x8 /* Abbrev Number: 8 (DW_TAG_array_type) */ ++ .long 0xa0 + (2f - 1f) /* DW_AT_type: DW_FORM_ref4 */ ++ .long 0x9d + (2f - 1f) /* DW_AT_sibling: DW_FORM_ref4 */ ++1: /* DW_AT_data_location: DW_FORM_block1: start */ ++ .byte 2f - 3f /* length */ ++3: ++ .byte 0x97 /* DW_OP_push_object_address */ ++ .byte 0x6 /* DW_OP_deref */ ++2: /* DW_AT_data_location: DW_FORM_block1: end */ ++ .uleb128 0x9 ++ .long 0x9d + (2b - 1b) /* DW_AT_type: DW_FORM_ref4 */ ++ .byte 0x3 ++ .byte 0x91 ++ .sleb128 -40 ++ .byte 0x6 ++ .byte 0x0 ++ .uleb128 0xa ++ .byte 0x8 ++ .byte 0x7 ++ .uleb128 0xb ++ .byte 0x1 ++ .byte 0x6 ++ .long .LASF1 ++ .byte 0x0 ++.Ldebug_end: ++ .section .debug_abbrev ++ .uleb128 0x1 ++ .uleb128 0x11 ++ .byte 0x1 ++ .uleb128 0x25 ++ .uleb128 0xe ++ .uleb128 0x13 ++ .uleb128 0xb ++ .uleb128 0x3 ++ .uleb128 0xe ++ .uleb128 0x1b ++ .uleb128 0xe ++ .uleb128 0x11 ++ .uleb128 0x1 ++ .uleb128 0x12 ++ .uleb128 0x1 ++ .uleb128 0x10 ++ .uleb128 0x6 ++ .byte 0x0 ++ .byte 0x0 ++ .uleb128 0x2 ++ .uleb128 0x2e ++ .byte 0x1 ++ .uleb128 0x3f ++ .uleb128 0xc ++ .uleb128 0x3 ++ .uleb128 0x8 ++ .uleb128 0x3a ++ .uleb128 0xb ++ .uleb128 0x3b ++ .uleb128 0xb ++ .uleb128 0x27 ++ .uleb128 0xc ++ .uleb128 0x11 ++ .uleb128 0x1 ++ .uleb128 0x12 ++ .uleb128 0x1 ++ .uleb128 0x40 ++ .uleb128 0x6 ++ .uleb128 0x1 ++ .uleb128 0x13 ++ .byte 0x0 ++ .byte 0x0 ++ .uleb128 0x3 ++ .uleb128 0x5 ++ .byte 0x0 ++ .uleb128 0x3 ++ .uleb128 0xe ++ .uleb128 0x3a ++ .uleb128 0xb ++ .uleb128 0x3b ++ .uleb128 0xb ++ .uleb128 0x49 ++ .uleb128 0x13 ++ .uleb128 0x2 ++ .uleb128 0xa ++ .byte 0x0 ++ .byte 0x0 ++ .uleb128 0x4 ++ .uleb128 0x16 ++ .byte 0x0 ++ .uleb128 0x3 ++ .uleb128 0xe ++ .uleb128 0x3a ++ .uleb128 0xb ++ .uleb128 0x3b ++ .uleb128 0xb ++ .uleb128 0x49 ++ .uleb128 0x13 ++ .byte 0x0 ++ .byte 0x0 ++ .uleb128 0x5 ++ .uleb128 0x34 ++ .byte 0x0 ++ .uleb128 0x3 ++ .uleb128 0xe ++ .uleb128 0x3a ++ .uleb128 0xb ++ .uleb128 0x3b ++ .uleb128 0xb ++ .uleb128 0x49 ++ .uleb128 0x13 ++ .uleb128 0x2 ++ .uleb128 0xa ++ .byte 0x0 ++ .byte 0x0 ++ .uleb128 0x6 ++ .uleb128 0x34 ++ .byte 0x0 ++ .uleb128 0x3 ++ .uleb128 0x8 ++ .uleb128 0x3a ++ .uleb128 0xb ++ .uleb128 0x3b ++ .uleb128 0xb ++ .uleb128 0x49 ++ .uleb128 0x13 ++ .uleb128 0x2 ++ .uleb128 0xa ++ .byte 0x0 ++ .byte 0x0 ++ .uleb128 0x7 ++ .uleb128 0x24 ++ .byte 0x0 ++ .uleb128 0xb ++ .uleb128 0xb ++ .uleb128 0x3e ++ .uleb128 0xb ++ .uleb128 0x3 ++ .uleb128 0x8 ++ .byte 0x0 ++ .byte 0x0 ++ .uleb128 0x8 /* Abbrev Number: 8 (DW_TAG_array_type) */ ++ .uleb128 0x1 ++ .byte 0x1 ++ .uleb128 0x49 /* DW_AT_type */ ++ .uleb128 0x13 /* DW_FORM_ref4 */ ++ .uleb128 0x1 /* DW_AT_sibling */ ++ .uleb128 0x13 /* DW_FORM_ref4 */ ++ .uleb128 0x50 /* DW_AT_data_location */ ++ .uleb128 0xa /* DW_FORM_block1 */ ++ .byte 0x0 ++ .byte 0x0 ++ .uleb128 0x9 ++ .uleb128 0x21 ++ .byte 0x0 ++ .uleb128 0x49 /* DW_AT_type */ ++ .uleb128 0x13 /* DW_FORM_ref4 */ ++ .uleb128 0x2f ++ .uleb128 0xa ++ .byte 0x0 ++ .byte 0x0 ++ .uleb128 0xa ++ .uleb128 0x24 ++ .byte 0x0 ++ .uleb128 0xb ++ .uleb128 0xb ++ .uleb128 0x3e ++ .uleb128 0xb ++ .byte 0x0 ++ .byte 0x0 ++ .uleb128 0xb ++ .uleb128 0x24 ++ .byte 0x0 ++ .uleb128 0xb ++ .uleb128 0xb ++ .uleb128 0x3e ++ .uleb128 0xb ++ .uleb128 0x3 ++ .uleb128 0xe ++ .byte 0x0 ++ .byte 0x0 ++ .byte 0x0 ++ .section .debug_pubnames,"",@progbits ++ .long 0x16 ++ .value 0x2 ++ .long .Ldebug_info0 ++ .long 0xa8 ++ .long 0x2d ++ .string "foo" ++ .long 0x0 ++ .section .debug_aranges,"",@progbits ++ .long 0x2c ++ .value 0x2 ++ .long .Ldebug_info0 ++ .byte 0x8 ++ .byte 0x0 ++ .value 0x0 ++ .value 0x0 ++ .quad .Ltext0 ++ .quad .Letext0-.Ltext0 ++ .quad 0x0 ++ .quad 0x0 ++ .section .debug_str,"MS",@progbits,1 ++.LASF0: ++ .string "array" ++.LASF5: ++ .string "size" ++.LASF3: ++ .string "x86_64-vla-typedef.c" ++.LASF6: ++ .string "array_t" ++.LASF1: ++ .string "char" ++.LASF4: ++ .string "gdb.arch" ++.LASF2: ++ .string "GNU C 4.3.2 20081105 (Red Hat 4.3.2-7)" ++ .ident "GCC: (GNU) 4.3.2 20081105 (Red Hat 4.3.2-7)" ++ .section .note.GNU-stack,"",@progbits +diff --git a/gdb/testsuite/gdb.arch/x86_64-vla-typedef.c b/gdb/testsuite/gdb.arch/x86_64-vla-typedef.c +new file mode 100644 +index 0000000..b809c4e +--- /dev/null ++++ b/gdb/testsuite/gdb.arch/x86_64-vla-typedef.c +@@ -0,0 +1,43 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2008 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++#if 0 ++ ++void ++foo (int size) ++{ ++ typedef char array_t[size]; ++ array_t array; ++ int i; ++ ++ for (i = 0; i < size; i++) ++ array[i] = i; ++ ++ array[0] = 0; /* break-here */ ++} ++ ++#else ++ ++int ++main (void) ++{ ++ foo (26); ++ foo (78); ++ return 0; ++} ++ ++#endif +diff --git a/gdb/testsuite/gdb.arch/x86_64-vla-typedef.exp b/gdb/testsuite/gdb.arch/x86_64-vla-typedef.exp +new file mode 100644 +index 0000000..534120a +--- /dev/null ++++ b/gdb/testsuite/gdb.arch/x86_64-vla-typedef.exp +@@ -0,0 +1,64 @@ ++# Copyright 2009 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++# Test DW_AT_data_location accessed through DW_TAG_typedef intermediate. ++ ++if ![istarget "x86_64-*-*"] then { ++ verbose "Skipping over gdb.arch/x86_64-vla-typedef.exp test made only for x86_64." ++ return ++} ++ ++set testfile x86_64-vla-typedef ++set srcasmfile ${testfile}-foo.S ++set srcfile ${testfile}.c ++set binfile ${objdir}/${subdir}/${testfile} ++set binobjfile ${objdir}/${subdir}/${testfile}-foo.o ++if { [gdb_compile "${srcdir}/${subdir}/${srcasmfile}" "${binobjfile}" object {}] != "" } { ++ untested "Couldn't compile test program" ++ return -1 ++} ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile} ${binobjfile}" "${binfile}" executable {debug}] != "" } { ++ untested "Couldn't compile test program" ++ return -1 ++} ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++if ![runto_main] { ++ untested x86_64-vla-typedef ++ return -1 ++} ++ ++gdb_breakpoint "break_here" ++ ++gdb_continue_to_breakpoint "break_here" ++ ++gdb_test "whatis array" "type = array_t" "first: whatis array" ++ ++gdb_test "ptype array" "type = char \\\[26\\\]" "first: ptype array" ++ ++gdb_test "p array\[1\]" "\\$\[0-9\] = 1 '\\\\1'" ++gdb_test "p array\[2\]" "\\$\[0-9\] = 2 '\\\\2'" ++gdb_test "p array\[3\]" "\\$\[0-9\] = 3 '\\\\3'" ++gdb_test "p array\[4\]" "\\$\[0-9\] = 4 '\\\\4'" ++ ++gdb_continue_to_breakpoint "break_here" ++ ++gdb_test "whatis array" "type = array_t" "second: whatis array" ++ ++gdb_test "ptype array" "type = char \\\[78\\\]" "second: ptype array" +diff --git a/gdb/testsuite/gdb.base/Makefile.in b/gdb/testsuite/gdb.base/Makefile.in +index 9f382db..12db521 100644 +--- a/gdb/testsuite/gdb.base/Makefile.in ++++ b/gdb/testsuite/gdb.base/Makefile.in +@@ -12,7 +12,7 @@ EXECUTABLES = all-types annota1 bitfields break \ + scope section_command setshow setvar shmain sigall signals \ + solib solib_sl so-impl-ld so-indr-cl \ + step-line step-test structs structs2 \ +- twice-tmp varargs vforked-prog watchpoint whatis ++ twice-tmp varargs vforked-prog watchpoint whatis catch-syscall + + MISCELLANEOUS = coremmap.data ../foobar.baz \ + shr1.sl shr2.sl solib_sl.sl solib1.sl solib2.sl +diff --git a/gdb/testsuite/gdb.base/call-rt-st.exp b/gdb/testsuite/gdb.base/call-rt-st.exp +index 3359c70..f73dd7f 100644 +--- a/gdb/testsuite/gdb.base/call-rt-st.exp ++++ b/gdb/testsuite/gdb.base/call-rt-st.exp +@@ -186,7 +186,7 @@ if {![gdb_skip_float_test "print print_two_floats(*f3)"] && \ + + if ![gdb_skip_stdio_test "print print_bit_flags_char(*cflags)"] { + print_struct_call "print_bit_flags_char(*cflags)" \ +- ".*alpha\[ \r\n\]+gamma\[ \r\n\]+epsilon\[ \r\n\]+.\[0-9\]+ = \\{alpha = 1 '\\\\001', beta = 0 '\\\\0', gamma = 1 '\\\\001', delta = 0 '\\\\0', epsilon = 1 '\\\\001', omega = 0 '\\\\0'\\}" ++ ".*alpha\[ \r\n\]+gamma\[ \r\n\]+epsilon\[ \r\n\]+.\[0-9\]+ = \\{alpha = 1 '\\\\1', beta = 0 '\\\\0', gamma = 1 '\\\\1', delta = 0 '\\\\0', epsilon = 1 '\\\\1', omega = 0 '\\\\0'\\}" + } + + if ![gdb_skip_stdio_test "print print_bit_flags_short(*sflags)"] { +diff --git a/gdb/testsuite/gdb.base/callfuncs.exp b/gdb/testsuite/gdb.base/callfuncs.exp +index 6d8aa45..be6a872 100644 +--- a/gdb/testsuite/gdb.base/callfuncs.exp ++++ b/gdb/testsuite/gdb.base/callfuncs.exp +@@ -437,7 +437,7 @@ gdb_test "print t_small_values(1,3,5,7,9,11,13,15,17,19)" \ + "The program being debugged stopped while.*" \ + "stop at nested call level 4" + gdb_test "backtrace" \ +- "\#0 t_small_values \\(arg1=1 '.001', arg2=3, arg3=5, arg4=7 '.a', arg5=9, arg6=11 '.v', arg7=13, arg8=15, arg9=17, arg10=19\\).*\#2 sum10 \\(i0=2, i1=4, i2=6, i3=8, i4=10, i5=12, i6=14, i7=16, i8=18, i9=20\\).*\#3 .*\#4 add \\(a=4, b=5\\).*\#5 .*\#6 add \\(a=2, b=3\\).*\#7 .*\#8 main.*" \ ++ "\#0 t_small_values \\(arg1=1 '.1', arg2=3, arg3=5, arg4=7 '.a', arg5=9, arg6=11 '.v', arg7=13, arg8=15, arg9=17, arg10=19\\).*\#2 sum10 \\(i0=2, i1=4, i2=6, i3=8, i4=10, i5=12, i6=14, i7=16, i8=18, i9=20\\).*\#3 .*\#4 add \\(a=4, b=5\\).*\#5 .*\#6 add \\(a=2, b=3\\).*\#7 .*\#8 main.*" \ + "backtrace at nested call level 4" + gdb_test "finish" "Value returned is .* = 100" \ + "Finish from nested call level 4" +diff --git a/gdb/testsuite/gdb.base/catch-syscall.c b/gdb/testsuite/gdb.base/catch-syscall.c +new file mode 100644 +index 0000000..64850de +--- /dev/null ++++ b/gdb/testsuite/gdb.base/catch-syscall.c +@@ -0,0 +1,25 @@ ++/* This file is used to test the 'catch syscall' feature on GDB. ++ ++ Please, if you are going to edit this file DO NOT change the syscalls ++ being called (nor the order of them). If you really must do this, then ++ take a look at catch-syscall.exp and modify there too. ++ ++ Written by Sergio Durigan Junior ++ September, 2008 */ ++ ++#include ++#include ++#include ++ ++int ++main (void) ++{ ++ /* A close() with a wrong argument. We are only ++ interested in the syscall. */ ++ close (-1); ++ ++ chroot ("."); ++ ++ /* The last syscall. Do not change this. */ ++ _exit (0); ++} +diff --git a/gdb/testsuite/gdb.base/catch-syscall.exp b/gdb/testsuite/gdb.base/catch-syscall.exp +new file mode 100644 +index 0000000..a9f6937 +--- /dev/null ++++ b/gdb/testsuite/gdb.base/catch-syscall.exp +@@ -0,0 +1,386 @@ ++# Copyright 1997, 1999, 2007, 2008 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++ ++# This program tests the 'catch syscall' functionality. ++# ++# It was written by Sergio Durigan Junior ++# on September/2008. ++ ++if { [is_remote target] || ![isnative] } then { ++ continue ++} ++ ++set prms_id 0 ++set bug_id 0 ++ ++global srcfile ++set testfile "catch-syscall" ++set srcfile ${testfile}.c ++set binfile ${objdir}/${subdir}/${testfile} ++ ++# All (but the last) syscalls from the example code ++# They are ordered according to the file, so do not change this. ++set all_syscalls { "close" "chroot" } ++# The last syscall (exit()) does not return, so ++# we cannot expect the catchpoint to be triggered ++# twice. It is a special case. ++set last_syscall "exit_group" ++ ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { ++ untested catch-syscall.exp ++ return -1 ++} ++ ++# Until "catch syscall" is implemented on other targets... ++if {![istarget "hppa*-hp-hpux*"] && ![istarget "*-linux*"]} then { ++ continue ++} ++ ++# This shall be updated whenever 'catch syscall' is implemented ++# on some architecture. ++#if { ![istarget "x86_64-*-linux*"] && ![istarget "i\[34567\]86-*-linux*"] ++if { ![istarget "i\[34567\]86-*-linux*"] ++ && ![istarget "powerpc-*-linux*"] && ![istarget "powerpc64-*-linux*"] } { ++ continue ++} ++ ++# Internal procedure used to check if, before any syscall is caught, ++# the command 'info breakpoints' correctly lists the catchpoints AND ++# says that nothing was caught yet. ++proc check_init_info_breakpoints {} { ++ global gdb_prompt ++ ++ # Verifying that the catchpoint appears in the 'info breakpoints' ++ # command, but with "". ++ set thistest "catch syscall appears in 'info breakpoints'" ++ gdb_test "info breakpoints" ".*catchpoint.*keep y.*syscall \"\".*" $thistest ++} ++ ++# This procedure checks if, after a syscall catchpoint is hit, the ++# command 'info breakpoints' correctly lists the syscall name. ++proc check_info_breakpoints { syscall } { ++ global gdb_prompt ++ ++ set thistest "syscall $syscall appears in 'info breakpoints'" ++ gdb_test "info breakpoints" ".*catchpoint.*keep y.*syscall (.)?${syscall}(.)?.*" $thistest ++} ++ ++# This procedure checks if there was a call to a syscall. ++proc check_call_to_syscall { syscall } { ++ global gdb_prompt ++ ++ set thistest "program has called $syscall" ++ gdb_test "continue" "Catchpoint .*(call to syscall .?${syscall}.?).*" $thistest ++ ++ # Checking if the syscall is reported to be caught in ++ # 'info breakpoints'. ++ check_info_breakpoints "$syscall" ++} ++ ++# This procedure checks if the syscall returned. ++proc check_return_from_syscall { syscall } { ++ global gdb_prompt ++ ++ set thistest "syscall $syscall has returned" ++ gdb_test "continue" "Catchpoint .*(returned from syscall (.)?${syscall}(.)?).*" $thistest ++ ++ # Checking if the syscall is reported to be caught in ++ # 'info breakpoints'. ++ check_info_breakpoints "$syscall" ++} ++ ++# Internal procedure that performs two 'continue' commands and checks if ++# a syscall call AND return occur. ++proc check_continue { syscall } { ++ global gdb_prompt ++ ++ # Testing if the 'continue' stops at the ++ # specified syscall_name. If it does, then it should ++ # first print that the infeior has called the syscall, ++ # and after print that the syscall has returned. ++ ++ # Testing if the inferiorr has called the syscall. ++ check_call_to_syscall $syscall ++ # And now, that the syscall has returned. ++ check_return_from_syscall $syscall ++} ++ ++# Inserts a syscall catchpoint with an argument. ++proc insert_catch_syscall_with_arg { syscall } { ++ global gdb_prompt ++ ++ # Trying to set the syscall ++ set thistest "catch syscall with arguments ($syscall)" ++ gdb_test "catch syscall $syscall" "Catchpoint .*(syscall\[(\]s\[)\] (.)?${syscall}(.)?).*" $thistest ++} ++ ++proc check_for_program_end {} { ++ global gdb_prompt ++ ++ # Deleting the catchpoints ++ delete_breakpoints ++ ++ set thistest "successful program end" ++ gdb_test "continue" "Program exited normally.*" $thistest ++ ++} ++ ++proc test_catch_syscall_without_args {} { ++ global gdb_prompt all_syscalls last_syscall ++ ++ # Trying to set the syscall ++ set thistest "setting catch syscall without arguments" ++ gdb_test "catch syscall" "Catchpoint .*(syscall).*" $thistest ++ ++ check_init_info_breakpoints ++ ++ # We have to check every syscall ++ foreach name $all_syscalls { ++ check_continue $name ++ } ++ ++ # At last but not least, we check if the inferior ++ # has called the last (exit) syscall. ++ check_call_to_syscall $last_syscall ++ ++ # Now let's see if the inferior correctly finishes. ++ check_for_program_end ++} ++ ++proc test_catch_syscall_with_args {} { ++ global gdb_prompt ++ set syscall_name "close" ++ ++ insert_catch_syscall_with_arg $syscall_name ++ check_init_info_breakpoints ++ ++ # Can we continue until we catch the syscall? ++ check_continue $syscall_name ++ ++ # Now let's see if the inferior correctly finishes. ++ check_for_program_end ++} ++ ++proc test_catch_syscall_with_wrong_args {} { ++ global gdb_prompt ++ # mlock is not called from the source ++ set syscall_name "mlock" ++ ++ insert_catch_syscall_with_arg $syscall_name ++ check_init_info_breakpoints ++ ++ # Now, we must verify if the program stops with a continue. ++ # If it doesn't, everything is right (since we don't have ++ # a syscall named "mlock" in it). Otherwise, this is a failure. ++ set thistest "catch syscall with unused syscall ($syscall_name)" ++ gdb_test "continue" "Program exited normally.*" $thistest ++} ++ ++proc test_catch_syscall_restarting_inferior {} { ++ global gdb_prompt ++ set syscall_name "chroot" ++ ++ insert_catch_syscall_with_arg $syscall_name ++ check_init_info_breakpoints ++ ++ # Let's first reach the call of the syscall. ++ check_call_to_syscall $syscall_name ++ ++ # Now, restart the program ++ rerun_to_main ++ ++ # And check for call/return ++ check_continue $syscall_name ++ ++ # Can we finish? ++ check_for_program_end ++} ++ ++proc do_syscall_tests {} { ++ global gdb_prompt srcdir ++ ++ # First, we need to set GDB datadir. ++ send_gdb "maintenance set gdb_datadir $srcdir/..\n" ++ gdb_expect 10 { ++ -re "$gdb_prompt $" { ++ verbose "Setting GDB datadir to $srcdir/..." 2 ++ } ++ timeout { ++ error "Couldn't set GDB datadir." ++ } ++ } ++ ++ # Verify that the 'catch syscall' help is available ++ set thistest "help catch syscall" ++ gdb_test "help catch syscall" "Catch system calls.*" $thistest ++ ++ # Try to set a catchpoint to a nonsense syscall ++ set thistest "catch syscall to a nonsense syscall is prohibited" ++ gdb_test "catch syscall nonsense_syscall" "Unknown syscall name .*" $thistest ++ ++ # Testing the 'catch syscall' command without arguments. ++ # This test should catch any syscalls. ++ if [runto_main] then { test_catch_syscall_without_args } ++ ++ # Testing the 'catch syscall' command with arguments. ++ # This test should only catch the specified syscall. ++ if [runto_main] then { test_catch_syscall_with_args } ++ ++ # Testing the 'catch syscall' command with WRONG arguments. ++ # This test should not trigger any catchpoints. ++ if [runto_main] then { test_catch_syscall_with_wrong_args } ++ ++ # Testing the 'catch' syscall command during a restart of ++ # the inferior. ++ if [runto_main] then { test_catch_syscall_restarting_inferior } ++} ++ ++proc test_catch_syscall_fail_noxml {} { ++ global gdb_prompt ++ ++ # Sanitizing. ++ delete_breakpoints ++ ++ # Testing to see if we receive a warning when calling "catch syscall" ++ # without XML support. ++ set thistest "Catch syscall displays a warning when there is no XML support" ++ gdb_test "catch syscall" "warning: Could not open .*warning: Could not load the syscall XML file .*GDB will not be able to display syscall names.*Catchpoint .*(syscall).*" $thistest ++ ++ # Since the catchpoint was set, we must check if it's present at ++ # "info breakpoints" ++ check_init_info_breakpoints ++ ++ # Sanitizing. ++ delete_breakpoints ++} ++ ++proc test_catch_syscall_without_args_noxml {} { ++ # We will need the syscall names even not using it ++ # because we need to know know many syscalls are in ++ # the example file. ++ global gdb_prompt all_syscalls last_syscall ++ ++ delete_breakpoints ++ ++ set thistest "Catch syscall without arguments and without XML support" ++ gdb_test "catch syscall" "Catchpoint .*(syscall).*" ++ ++ # Now, we should be able to set a catchpoint, ++ # and GDB shall not display the warning anymore. ++ foreach name $all_syscalls { ++ # Unfortunately, we don't know the syscall number ++ # that will be caught because this information is ++ # arch-dependent. Thus, we try to catch anything ++ # similar to a number. ++ check_continue "\[0-9\]*" ++ } ++ ++ # At last but not least, we check if the inferior ++ # has called the last (exit) syscall. ++ check_call_to_syscall "\[0-9\]*" ++ ++ delete_breakpoints ++} ++ ++proc test_catch_syscall_with_args_noxml {} { ++ global gdb_prompt ++ ++ # The number of the "close" syscall. This is our ++ # options for a "long-estabilished" syscall in all ++ # Linux architectures, but unfortunately x86_64 and ++ # a few other platforms don't "follow the convention". ++ # Because of this, we need this ugly check :-(. ++ set close_number "" ++ if { [istarget "x86_64-*-linux*"] } { ++ set close_number "3" ++ } else { ++ set close_number "6" ++ } ++ ++ delete_breakpoints ++ ++ insert_catch_syscall_with_arg $close_number ++ check_init_info_breakpoints ++ ++ check_continue $close_number ++ ++ delete_breakpoints ++} ++ ++proc test_catch_syscall_with_wrong_args_noxml {} { ++ global gdb_prompt ++ ++ delete_breakpoints ++ ++ # Even without XML support, GDB should not accept unknown ++ # syscall names for the catchpoint. ++ set thistest "Catch a nonsense syscall without XML support" ++ gdb_test "catch syscall nonsense_syscall" "Unknown syscall name .nonsense_syscall.*" $thistest ++ ++ delete_breakpoints ++} ++ ++proc do_syscall_tests_without_xml {} { ++ global gdb_prompt srcdir ++ ++ # In this case, we don't need to set GDB's datadir because ++ # we want GDB to display only numbers, not names. So, let's ++ # begin with the tests. ++ ++ # The first test is to see if GDB displays a warning when we ++ # try to catch syscalls without the XML support. ++ test_catch_syscall_fail_noxml ++ ++ # Now, let's test if we can catch syscalls without XML support. ++ # We should succeed, but GDB is not supposed to print syscall names. ++ if [runto_main] then { test_catch_syscall_without_args_noxml } ++ ++ # The only valid argument "catch syscall" should accept is the ++ # syscall number, and not the name (since it can't translate a ++ # name to a number). ++ # ++ # It's worth mentioning that we only try to catch the syscall ++ # close(). This is because the syscall number is an arch-dependent ++ # information, so we can't assume that we know every syscall number ++ # in this system. Therefore, we have decided to use a "long-estabilished" ++ # system call, and close() just sounded the right choice :-). ++ if [runto_main] then { test_catch_syscall_with_args_noxml } ++ ++ # Now, we'll try to provide a syscall name (valid or not) to the command, ++ # and expect it to fail. ++ if [runto_main] then { test_catch_syscall_with_wrong_args_noxml } ++} ++ ++# Start with a fresh gdb ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++# Execute the tests, using XML support ++do_syscall_tests ++ ++# Restart gdb ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++# Execute the tests, without XML support. In this case, GDB will ++# only display syscall numbers, and not syscall names. ++do_syscall_tests_without_xml +diff --git a/gdb/testsuite/gdb.base/charset.c b/gdb/testsuite/gdb.base/charset.c +index b640702..55a50ce 100644 +--- a/gdb/testsuite/gdb.base/charset.c ++++ b/gdb/testsuite/gdb.base/charset.c +@@ -20,11 +20,6 @@ + Please email any bugs, comments, and/or additions to this file to: + bug-gdb@gnu.org */ + +-#include +-#include +-#include +- +- + /* X_string is a null-terminated string in the X charset whose + elements are as follows. X should be the name the `set charset' + command uses for the character set, in lower-case, with any +@@ -54,6 +49,21 @@ char iso_8859_1_string[NUM_CHARS]; + char ebcdic_us_string[NUM_CHARS]; + char ibm1047_string[NUM_CHARS]; + ++/* We make a phony wchar_t and then pretend that this platform uses ++ UCS-4 (or UCS-2, depending on the size -- same difference for the ++ purposes of this test). */ ++typedef unsigned int wchar_t; ++wchar_t ucs_4_string[NUM_CHARS]; ++ ++/* We also define a couple phony types for testing the u'' and U'' ++ support. It is ok if these have the wrong size on some platforms ++ -- the test case will skip the tests in that case. */ ++typedef unsigned short char16_t; ++typedef unsigned int char32_t; ++ ++/* Make sure to use the typedefs. */ ++char16_t uvar; ++char32_t Uvar; + + void + init_string (char string[], +@@ -62,7 +72,10 @@ init_string (char string[], + char line_feed, char carriage_return, char horizontal_tab, + char vertical_tab, char cent, char misc_ctrl) + { +- memset (string, x, NUM_CHARS); ++ int i; ++ ++ for (i = 0; i < NUM_CHARS; ++i) ++ string[i] = x; + string[0] = alert; + string[1] = backspace; + string[2] = form_feed; +@@ -85,13 +98,21 @@ fill_run (char string[], int start, int len, int first) + } + + ++void ++init_ucs4 () ++{ ++ int i; ++ ++ for (i = 0; i < NUM_CHARS; ++i) ++ ucs_4_string[i] = iso_8859_1_string[i] & 0xff; ++} ++ + int main () + { + #ifdef usestubs + set_debug_traps(); + breakpoint(); + #endif +- (void) malloc (1); + /* Initialize ascii_string. */ + init_string (ascii_string, + 120, +@@ -146,5 +167,7 @@ int main () + /* The digits, at least, are contiguous. */ + fill_run (ibm1047_string, 59, 10, 240); + +- puts ("All set!"); /* all strings initialized */ ++ init_ucs4 (); ++ ++ return 0; /* all strings initialized */ + } +diff --git a/gdb/testsuite/gdb.base/charset.exp b/gdb/testsuite/gdb.base/charset.exp +index fa26521..93f66c0 100644 +--- a/gdb/testsuite/gdb.base/charset.exp ++++ b/gdb/testsuite/gdb.base/charset.exp +@@ -47,13 +47,7 @@ proc parse_show_charset_output {testname} { + global gdb_prompt + + gdb_expect { +- -re "The current host and target character set is `(.*)'\\.\[\r\n\]+$gdb_prompt $" { +- set host_charset $expect_out(1,string) +- set target_charset $expect_out(1,string) +- set retlist [list $host_charset $target_charset] +- pass $testname +- } +- -re "The current host character set is `(.*)'\\.\[\r\n\]+The current target character set is `(.*)'\\.\[\r\n\]+$gdb_prompt $" { ++ -re "The host character set is \"(.*)\"\\.\[\r\n\]+The target character set is \"(.*)\"\\.\[\r\n\]+The target wide character set is \"(.*)\"\\.\[\r\n\]+$gdb_prompt $" { + set host_charset $expect_out(1,string) + set target_charset $expect_out(2,string) + set retlist [list $host_charset $target_charset] +@@ -81,79 +75,35 @@ proc parse_show_charset_output {testname} { + } + + +-# Try the various `show charset' commands. These are all aliases of each +-# other; `show target-charset' and `show host-charset' actually print +-# both the host and target charsets. ++# Try the various `show charset' commands. + + send_gdb "show charset\n" + set show_charset [parse_show_charset_output "show charset"] + + send_gdb "show target-charset\n" +-set show_target_charset [parse_show_charset_output "show target-charset"] ++set show_target_charset \ ++ [lindex [parse_show_charset_output "show target-charset"] 0] + +-if {[lsearch $show_charset $show_target_charset] >= 0} { ++if {[lsearch -exact $show_charset $show_target_charset] >= 0} { + pass "check `show target-charset' against `show charset'" + } else { + fail "check `show target-charset' against `show charset'" + } + + send_gdb "show host-charset\n" +-set show_host_charset [parse_show_charset_output "show host-charset"] ++set show_host_charset \ ++ [lindex [parse_show_charset_output "show host-charset"] 0] + +-if {[lsearch $show_charset $show_host_charset] >= 0} { ++if {[lsearch -exact $show_charset $show_host_charset] >= 0} { + pass "check `show host-charset' against `show charset'" + } else { + fail "check `show host-charset' against `show charset'" + } + +- +-# Get the list of supported (host) charsets as possible completions. +-send_gdb "set charset \t\t" +- +-# Check that we can at least use ASCII as a host character set. +-sleep 1 +-gdb_expect { +- -re "^set charset .*\r\nASCII.*\r\n$gdb_prompt set charset " { +- # We got the output that we wanted, including ASCII as possible +- # charset. Send a newline to get us back to the prompt. This will +- # also generate an error message. Let's not check here that the error +- # message makes sense, we do that below, as a separate testcase. +- send_gdb "\n" +- gdb_expect { +- -re ".*Requires an argument.*$gdb_prompt $" { +- pass "get valid character sets" +- } +- -re ".*$gdb_prompt $" { +- send_gdb "\n" +- gdb_expect { +- -re ".*$gdb_prompt $" { +- fail "get valid character sets" +- } +- } +- } +- timeout { +- fail "(timeout) get valid character sets" +- } +- } +- } +- -re ".*$gdb_prompt $" { +- # We got some output that ended with a regular prompt +- fail "get valid character sets" +- } +- -re ".*$gdb_prompt set charset.*$" { +- # We got some other output, send a cntrl-c to gdb to get us back +- # to the prompt. +- send_gdb "\003" +- fail "get valid character sets" +- } +- timeout { +- fail "get valid character sets (timeout)" +- } +-} +- + # Try a malformed `set charset'. ++# Also check that we can at least use ASCII as a host character set. + gdb_test "set charset" \ +- "Requires an argument. Valid arguments are.*" \ ++ "Requires an argument. Valid arguments are.* ASCII,.*" \ + "try malformed `set charset'" + + # Try using `set host-charset' on an invalid character set. +@@ -244,8 +194,10 @@ gdb_expect { + } + } + +-# Make sure that GDB supports every host/target charset combination. +-foreach host_charset [all_charset_names] { ++# We don't want to test all the charset names here, since that would ++# be too many combinations. We we pick a subset. ++set charset_subset {ASCII ISO-8859-1 EBCDIC-US IBM1047} ++foreach host_charset $charset_subset { + if {[valid_host_charset $host_charset]} { + + set testname "try `set host-charset $host_charset'" +@@ -279,7 +231,7 @@ foreach host_charset [all_charset_names] { + + # Now try setting every possible target character set, + # given that host charset. +- foreach target_charset [all_charset_names] { ++ foreach target_charset $charset_subset { + set testname "try `set target-charset $target_charset'" + send_gdb "set target-charset $target_charset\n" + gdb_expect { +@@ -404,23 +356,42 @@ gdb_expect { + } + + ++# We only try the wide character tests on machines where the wchar_t ++# typedef in the test case has the right size. ++set wchar_size [get_sizeof wchar_t 99] ++set wchar_ok 0 ++if {$wchar_size == 2} { ++ lappend charset_subset UCS-2 ++ set wchar_ok 1 ++} elseif {$wchar_size == 4} { ++ lappend charset_subset UCS-4 ++ set wchar_ok 1 ++} ++ + gdb_test "set host-charset ASCII" "" +-foreach target_charset [all_charset_names] { +- send_gdb "set target-charset $target_charset\n" ++foreach target_charset $charset_subset { ++ if {$target_charset == "UCS-4" || $target_charset == "UCS-2"} { ++ set param target-wide-charset ++ set L L ++ } else { ++ set param target-charset ++ set L "" ++ } ++ send_gdb "set $param $target_charset\n" + gdb_expect { + -re "$gdb_prompt $" { +- pass "set target-charset $target_charset" ++ pass "set $param $target_charset" + } + timeout { +- fail "set target-charset $target_charset (timeout)" ++ fail "set $param $target_charset (timeout)" + } + } + + # Try printing the null character. There seems to be a bug in + # gdb_test that requires us to use gdb_expect here. +- send_gdb "print '\\0'\n" ++ send_gdb "print $L'\\0'\n" + gdb_expect { +- -re "\\\$${decimal} = 0 '\\\\0'\[\r\n\]+$gdb_prompt $" { ++ -re "\\\$${decimal} = 0 $L'\\\\0'\[\r\n\]+$gdb_prompt $" { + pass "print the null character in ${target_charset}" + } + -re "$gdb_prompt $" { +@@ -435,8 +406,14 @@ foreach target_charset [all_charset_names] { + # a string in $target_charset. The variable's name is the + # character set's name, in lower-case, with all non-identifier + # characters replaced with '_', with "_string" stuck on the end. +- set var_name [string tolower "${target_charset}_string"] +- regsub -all -- "\[^a-z0-9_\]" $var_name "_" var_name ++ if {$target_charset == "UCS-2"} { ++ # We still use the ucs_4_string variable -- but the size is ++ # correct for UCS-2. ++ set var_name ucs_4_string ++ } else { ++ set var_name [string tolower "${target_charset}_string"] ++ regsub -all -- "\[^a-z0-9_\]" $var_name "_" var_name ++ } + + # Compute a regexp matching the results we expect. This is static, + # but it's easier than writing it out. +@@ -444,12 +421,12 @@ foreach target_charset [all_charset_names] { + set uppercase "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + set lowercase "abcdefghijklmnopqrstuvwxyz" + set digits "0123456789" +- set octal_escape "\\\\\[0-9\]\[0-9\]\[0-9\]" ++ set octal_escape "\\\\\[0-9\]+" + + send_gdb "print $var_name\n" + # ${escapes}${uppercase}${lowercase}${digits}${octal}${octal} + gdb_expect { +- -re ".* = \"(\\\\a|x)(\\\\b|x)(\\\\f|x)(\\\\n|x)(\\\\r|x)(\\\\t|x)(\\\\v|x)${uppercase}${lowercase}${digits}(\\\\\[0-9\]\[0-9\]\[0-9\]|x)(\\\\\[0-9\]\[0-9\]\[0-9\]|x).*\"\[\r\n\]+$gdb_prompt $" { ++ -re ".* = $L\"(\\\\a|x)(\\\\b|x)(\\\\f|x)(\\\\n|x)(\\\\r|x)(\\\\t|x)(\\\\v|x)${uppercase}${lowercase}${digits}(${octal_escape}|x)+\"\[\r\n\]+$gdb_prompt $" { + pass "print string in $target_charset" + } + -re "$gdb_prompt $" { +@@ -461,22 +438,22 @@ foreach target_charset [all_charset_names] { + } + + # Try entering a character literal, and see if it comes back unchanged. +- gdb_test "print 'A'" \ +- " = \[0-9-\]+ 'A'" \ ++ gdb_test "print $L'A'" \ ++ " = \[0-9-\]+ $L'A'" \ + "parse character literal in ${target_charset}" + + # Check that the character literal was encoded correctly. +- gdb_test "print 'A' == $var_name\[7\]" \ ++ gdb_test "print $L'A' == $var_name\[7\]" \ + " = 1" \ + "check value of parsed character literal in ${target_charset}" + + # Try entering a string literal, and see if it comes back unchanged. +- gdb_test "print \"abcdefABCDEF012345\"" \ +- " = \"abcdefABCDEF012345\"" \ ++ gdb_test "print $L\"abcdefABCDEF012345\"" \ ++ " = $L\"abcdefABCDEF012345\"" \ + "parse string literal in ${target_charset}" + + # Check that the string literal was encoded correctly. +- gdb_test "print \"q\"\[0\] == $var_name\[49\]" \ ++ gdb_test "print $L\"q\"\[0\] == $var_name\[49\]" \ + " = 1" \ + "check value of parsed string literal in ${target_charset}" + +@@ -509,7 +486,7 @@ foreach target_charset [all_charset_names] { + send_gdb "print $var_name\[$i\]\n" + set have_escape 1 + gdb_expect { +- -re "= \[0-9-\]+ '\\\\${escape}'\[\r\n\]+$gdb_prompt $" { ++ -re "= \[0-9-\]+ $L'\\\\${escape}'\[\r\n\]+$gdb_prompt $" { + pass "try printing '\\${escape}' in ${target_charset}" + } + -re "= \[0-9-\]+ 'x'\[\r\n\]+$gdb_prompt $" { +@@ -527,12 +504,12 @@ foreach target_charset [all_charset_names] { + if {$have_escape} { + + # Try parsing a backslash escape in a character literal. +- gdb_test "print '\\${escape}' == $var_name\[$i\]" \ ++ gdb_test "print $L'\\${escape}' == $var_name\[$i\]" \ + " = 1" \ + "check value of '\\${escape}' in ${target_charset}" + + # Try parsing a backslash escape in a string literal. +- gdb_test "print \"\\${escape}\"\[0\] == $var_name\[$i\]" \ ++ gdb_test "print $L\"\\${escape}\"\[0\] == $var_name\[$i\]" \ + " = 1" \ + "check value of \"\\${escape}\" in ${target_charset}" + } +@@ -540,10 +517,73 @@ foreach target_charset [all_charset_names] { + + # Try printing a character escape that doesn't exist. We should + # get the unescaped character, in the target character set. +- gdb_test "print '\\q'" " = \[0-9-\]+ 'q'" \ ++ gdb_test "print $L'\\q'" " = \[0-9-\]+ $L'q'" \ + "print escape that doesn't exist in $target_charset" +- gdb_test "print '\\q' == $var_name\[49\]" " = 1" \ ++ gdb_test "print $L'\\q' == $var_name\[49\]" " = 1" \ + "check value of escape that doesn't exist in $target_charset" + } + ++# Reset the target charset. ++gdb_test "set target-charset UTF-8" "" ++ ++# \242 is not a valid UTF-8 character. ++gdb_test "print \"\\242\"" " = \"\\\\242\"" \ ++ "non-representable target character" ++ ++gdb_test "print '\\x'" "\\\\x escape without a following hex digit." ++gdb_test "print '\\u'" "\\\\u escape without a following hex digit." ++gdb_test "print '\\9'" " = \[0-9\]+ '9'" ++ ++# Tests for wide- or unicode- strings. L is the prefix letter to use, ++# either "L" (for wide strings), "u" (for UCS-2), or "U" (for UCS-4). ++# NAME is used in the test names and should be related to the prefix ++# letter in some easy-to-undestand way. ++proc test_wide_or_unicode {L name} { ++ gdb_test "print $L\"ab\" $L\"c\"" " = $L\"abc\"" \ ++ "basic $name string concatenation" ++ gdb_test "print $L\"ab\" \"c\"" " = $L\"abc\"" \ ++ "narrow and $name string concatenation" ++ gdb_test "print \"ab\" $L\"c\"" " = $L\"abc\"" \ ++ "$name and narrow string concatenation" ++ gdb_test "print $L\"\\xe\" $L\"c\"" " = $L\"\\\\16c\"" \ ++ "$name string concatenation with escape" ++ gdb_test "print $L\"\" \"abcdef\" \"g\"" \ ++ "$L\"abcdefg\"" \ ++ "concatenate three strings with empty $name string" ++ ++ gdb_test "print $L'a'" "= \[0-9\]+ $L'a'" \ ++ "basic $name character" ++} ++ ++if {$wchar_ok} { ++ test_wide_or_unicode L wide ++} ++ ++set ucs2_ok [expr {[get_sizeof char16_t 99] == 2}] ++if {$ucs2_ok} { ++ test_wide_or_unicode u UCS-2 ++} ++ ++set ucs4_ok [expr {[get_sizeof char32_t 99] == 4}] ++if {$ucs4_ok} { ++ test_wide_or_unicode U UCS-4 ++} ++ ++# Test an invalid string combination. ++proc test_combination {L1 name1 L2 name2} { ++ gdb_test "print $L1\"abc\" $L2\"def\"" \ ++ "Undefined string concatenation." \ ++ "undefined concatenation of $name1 and $name2" ++} ++ ++if {$wchar_ok && $ucs2_ok} { ++ test_combination L wide u UCS-2 ++} ++if {$wchar_ok && $ucs4_ok} { ++ test_combination L wide U UCS-4 ++} ++if {$ucs2_ok && $ucs4_ok} { ++ test_combination u UCS-2 U UCS-4 ++} ++ + gdb_exit +diff --git a/gdb/testsuite/gdb.base/constvars.exp b/gdb/testsuite/gdb.base/constvars.exp +index d53a826..6d1bd12 100644 +--- a/gdb/testsuite/gdb.base/constvars.exp ++++ b/gdb/testsuite/gdb.base/constvars.exp +@@ -161,7 +161,7 @@ proc do_constvar_tests {} { + gdb_test "print laconic" " = 65 'A'" + local_compiler_xfail_check + gdb_test "ptype laconic" "type = const char" +- gdb_test "print laggard" " = 1 '.001'" ++ gdb_test "print laggard" " = 1 '.1'" + local_compiler_xfail_check + gdb_test "ptype laggard" "type = const unsigned char" + gdb_test "print lagoon" " = 2" +@@ -209,7 +209,7 @@ proc do_constvar_tests {} { + gdb_test "print *lewd" " = 65 'A'" + local_compiler_xfail_check + gdb_test "ptype lewd" "type = const char \\* const" +- gdb_test "print *lexicographer" " = 1 '.001'" ++ gdb_test "print *lexicographer" " = 1 '.1'" + local_compiler_xfail_check + gdb_test "ptype lexicographer" "type = const unsigned char \\* const" + gdb_test "print *lexicon" " = 2" +@@ -233,7 +233,7 @@ proc do_constvar_tests {} { + gdb_test "print *languish" " = 65 'A'" + local_compiler_xfail_check + gdb_test "ptype languish" "type = const char \\*" +- gdb_test "print *languor" " = 1 '.001'" ++ gdb_test "print *languor" " = 1 '.1'" + local_compiler_xfail_check + gdb_test "ptype languor" "type = const unsigned char \\*" + gdb_test "print *lank" " = 2" +diff --git a/gdb/testsuite/gdb.base/display.exp b/gdb/testsuite/gdb.base/display.exp +index d62e8bf..aa65373 100644 +--- a/gdb/testsuite/gdb.base/display.exp ++++ b/gdb/testsuite/gdb.base/display.exp +@@ -180,8 +180,12 @@ gdb_test "printf \"%p\\n\", 1" "0x1" + + # play with "print", too + # +-gdb_test "print/r j" ".*Undefined output format.*" +-gdb_test "print j" ".*" "debug test output" ++gdb_test "print/z j" ".*Undefined output format.*" ++gdb_test "print/d j" " = 0\[\\r\\n\]+" "debug test output 1" ++gdb_test "print/r j" " = 0\[\\r\\n\]+" "debug test output 1a" ++gdb_test "print/x j" " = 0x0\[\\r\\n\]+" "debug test output 2" ++gdb_test "print/r j" " = 0x0\[\\r\\n\]+" "debug test output 2a" ++gdb_test "print j" " = 0\[\\r\\n\]+" "debug test output 3" + + # x/0 j doesn't produce any output and terminates PA64 process when testing + if [istarget "hppa2.0w-hp-hpux11*"] { +diff --git a/gdb/testsuite/gdb.base/help.exp b/gdb/testsuite/gdb.base/help.exp +index 4618a2c..40830c3 100644 +--- a/gdb/testsuite/gdb.base/help.exp ++++ b/gdb/testsuite/gdb.base/help.exp +@@ -603,7 +603,7 @@ gdb_test "help stepi" "Step one instruction exactly\.\[\r\n\]+Argument N means d + gdb_test "help signal" "Continue program giving it signal.*" "help signal" + # test help source + # vxgdb reads .vxgdbinit +-gdb_test "help source" "Read commands from a file named FILE\.\[\r\n\]+Optional -v switch \\(before the filename\\) causes each command in\[\r\n\]+FILE to be echoed as it is executed\.\[\r\n\]+Note that the file \"\[^\"\]*\" is read automatically in this way\[\r\n\]+when GDB is started\." "help source" ++gdb_test "help source" "Read commands from a file named FILE\.\[\r\n\]+Optional -v switch \\(before the filename\\) causes each command in\[\r\n\]+FILE to be echoed as it is executed\.\[\r\n\]+Note that the file \"\[^\"\]*\" is read automatically in this way\[\r\n\]+when GDB is started\.\[\r\n\]+Optional -p switch \\(before the filename\\) causes FILE to be evaluated\[\r\n\]+as Python code\." "help source" + # test help stack + test_class_help "stack" { + "Examining the stack\..*\[\r\n\]+" +diff --git a/gdb/testsuite/gdb.base/lineno-makeup-func.c b/gdb/testsuite/gdb.base/lineno-makeup-func.c +new file mode 100644 +index 0000000..1a0220e +--- /dev/null ++++ b/gdb/testsuite/gdb.base/lineno-makeup-func.c +@@ -0,0 +1,21 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2009 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++void ++func (void) ++{ ++} +diff --git a/gdb/testsuite/gdb.base/lineno-makeup.c b/gdb/testsuite/gdb.base/lineno-makeup.c +new file mode 100644 +index 0000000..bb20e98 +--- /dev/null ++++ b/gdb/testsuite/gdb.base/lineno-makeup.c +@@ -0,0 +1,35 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2009 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++/* DW_AT_low_pc-DW_AT_high_pc should cover the function without line number ++ information (.debug_line) so we cannot use an external object file. ++ ++ It must not be just a label as it would alias on the next function even for ++ correct GDB. Therefore some stub data must be placed there. ++ ++ We need to provide a real stub function body as at least s390 ++ (s390_analyze_prologue) would skip the whole body till reaching `main'. */ ++ ++extern void func (void); ++asm ("func: .incbin \"gdb.base/lineno-makeup-func.bin\""); ++ ++int ++main (void) ++{ ++ func (); ++ return 0; ++} +diff --git a/gdb/testsuite/gdb.base/lineno-makeup.exp b/gdb/testsuite/gdb.base/lineno-makeup.exp +new file mode 100644 +index 0000000..0c75b84 +--- /dev/null ++++ b/gdb/testsuite/gdb.base/lineno-makeup.exp +@@ -0,0 +1,78 @@ ++# Copyright 2009 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++set testfile "lineno-makeup" ++set srcfuncfile ${testfile}-func.c ++set srcfile ${testfile}.c ++set objfuncfile ${objdir}/${subdir}/${testfile}-func.o ++set binfuncfile ${objdir}/${subdir}/${testfile}-func.bin ++set binfile ${objdir}/${subdir}/${testfile} ++ ++if { [gdb_compile "${srcdir}/${subdir}/${srcfuncfile}" "${objfuncfile}" object {}] != "" } { ++ gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail." ++} ++ ++set objcopy [catch "exec objcopy -O binary --only-section .text ${objfuncfile} ${binfuncfile}" output] ++verbose -log "objcopy=$objcopy: $output" ++if { $objcopy != 0 } { ++ gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail." ++} ++set binfuncfilesize [file size $binfuncfile] ++verbose -log "file size $binfuncfile = $binfuncfilesize" ++ ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { ++ gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail." ++} ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++set b_addr "" ++set test "break func" ++gdb_test_multiple $test $test { ++ -re "Breakpoint \[0-9\]+ at (0x\[0-9a-f\]+)\r\n$gdb_prompt $" { ++ set b_addr $expect_out(1,string) ++ pass $test ++ } ++ -re "Breakpoint \[0-9\]+ at (0x\[0-9a-f\]+): .*\r\n$gdb_prompt $" { ++ set b_addr $expect_out(1,string) ++ fail $test ++ } ++} ++verbose -log "b_addr=<$b_addr>" ++ ++set p_addr "" ++set test "print func" ++gdb_test_multiple $test $test { ++ -re "\\$\[0-9\]+ = {} (0x\[0-9a-f\]+) \r\n$gdb_prompt $" { ++ set p_addr $expect_out(1,string) ++ pass $test ++ } ++} ++verbose -log "p_addr=<$p_addr>" ++ ++set test "break address belongs to func" ++if {$b_addr == $p_addr} { ++ pass "$test (exact match)" ++} else { ++ set skip [expr $b_addr - $p_addr] ++ if {$skip > 0 && $skip < $binfuncfilesize} { ++ pass "$test (prologue skip by $skip bytes)" ++ } else { ++ fail $test ++ } ++} +diff --git a/gdb/testsuite/gdb.base/long_long.exp b/gdb/testsuite/gdb.base/long_long.exp +index d0ad5ba..5189324 100644 +--- a/gdb/testsuite/gdb.base/long_long.exp ++++ b/gdb/testsuite/gdb.base/long_long.exp +@@ -210,7 +210,7 @@ gdb_test_char "p/o *(char *)c" "01" + gdb_test_char "p/t *(char *)c" "1" + gdb_test_char "p/a *(char *)c" "0x1( <.*>)?" + gdb_test_char "p/f *(char *)c" "1" +-gdb_test_char "p/c *(char *)c" "1 '.001'" ++gdb_test_char "p/c *(char *)c" "1 '.1'" + + gdb_test_short "p/x *(short *)s" "" "0x123" "" + gdb_test_short "p/d *(short *)s" "" "291" "" +@@ -257,7 +257,7 @@ gdb_test "x/u w" "19088743" + gdb_test "x/o w" "0110642547" + gdb_test "x/t w" "00000001001000110100010101100111" + gdb_test_xptr "x/a" { b "" } { h "" } { w "0x1234567" } { g "0x123456789abcdef" } +-gdb_test "x/c b" "1 '.001'" ++gdb_test "x/c b" "1 '.1'" + if { $sizeof_double == 8 || $sizeof_long_double == 8 } { + gdb_test "x/f &val.oct" "-5.9822653797615723e-120" + } else { +@@ -273,7 +273,7 @@ gdb_test "x/2u g" "81985529216486895.*12046818088235383159" + gdb_test "x/2o g" "04432126361152746757.*01234567123456701234567" + gdb_test "x/2t g" "0000000100100011010001010110011110001001101010111100110111101111.*1010011100101110111001010011100101110111000001010011100101110111" + gdb_test_xptr "x/2a" { b "" } { h "" } { w "0x1234567.*0xa72ee539" } { g "0x123456789abcdef.*0xa72ee53977053977" } +-gdb_test "x/2c b" "1 '.001'.*-89 '.'" ++gdb_test "x/2c b" "1 '.1'.*-89 '.\[0-9\]*'" + if { $sizeof_double == 8 || $sizeof_long_double == 8 } { + gdb_test "x/2f &val.oct" "-5.9822653797615723e-120.*-5.9041889495880968e-100" + } else { +@@ -288,7 +288,7 @@ gdb_test "x/2bu b" "1.*167" + gdb_test "x/2bo b" "01.*0247" + gdb_test "x/2bt b" "00000001.*10100111" + gdb_test_ptr "x/2ba b" "" "" "0x1.*0xffffffa7" "0x1.*0xffffffffffffffa7" +-gdb_test "x/2bc b" "1 '.001'.*-89 '.'" ++gdb_test "x/2bc b" "1 '.1'.*-89 '.\[0-9\]*'" + gdb_test "x/2bf b" "1.*-89" + + gdb_test "x/2hx h" "0x0123.*0xa72e" +@@ -315,7 +315,7 @@ gdb_test "x/2gu g" "81985529216486895.*12046818088235383159" + gdb_test "x/2go g" "04432126361152746757.*01234567123456701234567" + gdb_test "x/2gt g" "0000000100100011010001010110011110001001101010111100110111101111.*1010011100101110111001010011100101110111000001010011100101110111" + gdb_test_ptr "x/2ga g" "" "" "0x89abcdef.*0x77053977" "0x123456789abcdef.*0xa72ee53977053977" +-gdb_test "x/2gc g" "-17 '.'.*119 'w'" ++gdb_test "x/2gc g" "-17 '.\[0-9\]*'.*119 'w'" + gdb_test "x/2gf g" "3.5127005640885037e-303.*-5.9822653797615723e-120" + + gdb_exit +diff --git a/gdb/testsuite/gdb.base/macscp.exp b/gdb/testsuite/gdb.base/macscp.exp +index 7086e90..dd196d7 100644 +--- a/gdb/testsuite/gdb.base/macscp.exp ++++ b/gdb/testsuite/gdb.base/macscp.exp +@@ -26,13 +26,21 @@ set testfile "macscp" + set objfile ${objdir}/${subdir}/${testfile}.o + set binfile ${objdir}/${subdir}/${testfile} + +-set options { debug } ++set options { debug additional_flags=-DFROM_COMMANDLINE=ARG} + + get_compiler_info ${binfile} + if [test_compiler_info gcc*] { + lappend options additional_flags=-g3 + } + ++# Workaround ccache making lineno non-zero for command-line definitions. ++if {[find_gcc] == "gcc" && [file executable "/usr/bin/gcc"]} { ++ set result [catch "exec which gcc" output] ++ if {$result == 0 && [string first "/ccache/" $output] >= -1} { ++ lappend options "compiler=/usr/bin/gcc" ++ } ++} ++ + # Generate the intermediate object file. This is required by Darwin to + # have access to the .debug_macinfo section. + if {[gdb_compile "${srcdir}/${subdir}/macscp1.c" "${objfile}" \ +@@ -79,11 +87,15 @@ proc info_macro {macro} { + + if {$debug_me} {exp_internal 1} + gdb_expect { +- -re "Defined at \[^\r\n\]*(${filepat}):${decimal}\[\r\n\]" { ++ -re "Defined at \[^\r\n\]*(${filepat}):(${decimal})\[\r\n\]" { + # `location' and `definition' should be empty when we see + # this message. + if {[llength $location] == 0 && [llength $definition] == 0} { + set location $expect_out(1,string) ++ # Definitions from gcc command-line get suffixed by the lineno. ++ if {$expect_out(2,string) == "0" } { ++ set location "$location:$expect_out(2,string)" ++ } + exp_continue + } else { + # Exit this expect loop, with a result indicating failure. +@@ -198,6 +210,8 @@ proc list_and_check_macro {func macro expected} { + } + + ++list_and_check_macro main FROM_COMMANDLINE "macscp1.c:0 ARG" ++ + if {[list_and_check_macro main WHERE {macscp1.c {before macscp1_3}}]} { + return 0 + } +diff --git a/gdb/testsuite/gdb.base/nodebug.exp b/gdb/testsuite/gdb.base/nodebug.exp +index 4c01be4..31fb88e 100644 +--- a/gdb/testsuite/gdb.base/nodebug.exp ++++ b/gdb/testsuite/gdb.base/nodebug.exp +@@ -215,5 +215,12 @@ if [runto inner] then { + if [runto middle] then { + gdb_test "backtrace 10" "#0.*middle.*#1.*top.*#2.*main.*" \ + "backtrace from middle in nodebug.exp" ++ ++ # Test return from a function with no debug info (symbol; still it may ++ # have a minimal-symbol). In gdb.base/return*.exp we would need to ++ # build a separate executable with no "debug" option. ++ gdb_test "return 0" "#0 .* top \\(.*" \ ++ "return from function with no debug info" \ ++ "Make selected stack frame return now\\? \\(y or n\\) " "y" + } + } +diff --git a/gdb/testsuite/gdb.base/pointers.exp b/gdb/testsuite/gdb.base/pointers.exp +index 91838a2..2d0a70e 100644 +--- a/gdb/testsuite/gdb.base/pointers.exp ++++ b/gdb/testsuite/gdb.base/pointers.exp +@@ -389,7 +389,7 @@ gdb_expect { + + send_gdb "print *pUC\n" + gdb_expect { +- -re ".\[0-9\]* = 21 \'.025\'.*$gdb_prompt $" { ++ -re ".\[0-9\]* = 21 \'.25\'.*$gdb_prompt $" { + pass "print value of *pUC" + } + -re ".*$gdb_prompt $" { fail "print value of *pUC" } +diff --git a/gdb/testsuite/gdb.base/printcmds.exp b/gdb/testsuite/gdb.base/printcmds.exp +index 1e17da4..b6f8a1f 100644 +--- a/gdb/testsuite/gdb.base/printcmds.exp ++++ b/gdb/testsuite/gdb.base/printcmds.exp +@@ -137,12 +137,12 @@ proc test_print_all_chars {} { + global gdb_prompt + + gdb_test "p ctable1\[0\]" " = 0 '\\\\0'" +- gdb_test "p ctable1\[1\]" " = 1 '\\\\001'" +- gdb_test "p ctable1\[2\]" " = 2 '\\\\002'" +- gdb_test "p ctable1\[3\]" " = 3 '\\\\003'" +- gdb_test "p ctable1\[4\]" " = 4 '\\\\004'" +- gdb_test "p ctable1\[5\]" " = 5 '\\\\005'" +- gdb_test "p ctable1\[6\]" " = 6 '\\\\006'" ++ gdb_test "p ctable1\[1\]" " = 1 '\\\\1'" ++ gdb_test "p ctable1\[2\]" " = 2 '\\\\2'" ++ gdb_test "p ctable1\[3\]" " = 3 '\\\\3'" ++ gdb_test "p ctable1\[4\]" " = 4 '\\\\4'" ++ gdb_test "p ctable1\[5\]" " = 5 '\\\\5'" ++ gdb_test "p ctable1\[6\]" " = 6 '\\\\6'" + gdb_test "p ctable1\[7\]" " = 7 '\\\\a'" + gdb_test "p ctable1\[8\]" " = 8 '\\\\b'" + gdb_test "p ctable1\[9\]" " = 9 '\\\\t'" +@@ -150,24 +150,24 @@ proc test_print_all_chars {} { + gdb_test "p ctable1\[11\]" " = 11 '\\\\v'" + gdb_test "p ctable1\[12\]" " = 12 '\\\\f'" + gdb_test "p ctable1\[13\]" " = 13 '\\\\r'" +- gdb_test "p ctable1\[14\]" " = 14 '\\\\016'" +- gdb_test "p ctable1\[15\]" " = 15 '\\\\017'" +- gdb_test "p ctable1\[16\]" " = 16 '\\\\020'" +- gdb_test "p ctable1\[17\]" " = 17 '\\\\021'" +- gdb_test "p ctable1\[18\]" " = 18 '\\\\022'" +- gdb_test "p ctable1\[19\]" " = 19 '\\\\023'" +- gdb_test "p ctable1\[20\]" " = 20 '\\\\024'" +- gdb_test "p ctable1\[21\]" " = 21 '\\\\025'" +- gdb_test "p ctable1\[22\]" " = 22 '\\\\026'" +- gdb_test "p ctable1\[23\]" " = 23 '\\\\027'" +- gdb_test "p ctable1\[24\]" " = 24 '\\\\030'" +- gdb_test "p ctable1\[25\]" " = 25 '\\\\031'" +- gdb_test "p ctable1\[26\]" " = 26 '\\\\032'" +- gdb_test "p ctable1\[27\]" " = 27 '\\\\033'" +- gdb_test "p ctable1\[28\]" " = 28 '\\\\034'" +- gdb_test "p ctable1\[29\]" " = 29 '\\\\035'" +- gdb_test "p ctable1\[30\]" " = 30 '\\\\036'" +- gdb_test "p ctable1\[31\]" " = 31 '\\\\037'" ++ gdb_test "p ctable1\[14\]" " = 14 '\\\\16'" ++ gdb_test "p ctable1\[15\]" " = 15 '\\\\17'" ++ gdb_test "p ctable1\[16\]" " = 16 '\\\\20'" ++ gdb_test "p ctable1\[17\]" " = 17 '\\\\21'" ++ gdb_test "p ctable1\[18\]" " = 18 '\\\\22'" ++ gdb_test "p ctable1\[19\]" " = 19 '\\\\23'" ++ gdb_test "p ctable1\[20\]" " = 20 '\\\\24'" ++ gdb_test "p ctable1\[21\]" " = 21 '\\\\25'" ++ gdb_test "p ctable1\[22\]" " = 22 '\\\\26'" ++ gdb_test "p ctable1\[23\]" " = 23 '\\\\27'" ++ gdb_test "p ctable1\[24\]" " = 24 '\\\\30'" ++ gdb_test "p ctable1\[25\]" " = 25 '\\\\31'" ++ gdb_test "p ctable1\[26\]" " = 26 '\\\\32'" ++ gdb_test "p ctable1\[27\]" " = 27 '\\\\33'" ++ gdb_test "p ctable1\[28\]" " = 28 '\\\\34'" ++ gdb_test "p ctable1\[29\]" " = 29 '\\\\35'" ++ gdb_test "p ctable1\[30\]" " = 30 '\\\\36'" ++ gdb_test "p ctable1\[31\]" " = 31 '\\\\37'" + gdb_test "p ctable1\[32\]" " = 32 ' '" + gdb_test "p ctable1\[33\]" " = 33 '!'" + gdb_test "p ctable1\[34\]" " = 34 '\"'" +@@ -475,13 +475,13 @@ proc test_print_strings {} { + gdb_test "p &ctable1\[0\]" \ + " = \\(unsigned char \\*\\) \"\"" + gdb_test "p &ctable1\[1\]" \ +- " = \\(unsigned char \\*\\) \"\\\\001\\\\002\\\\003\\\\004\\\\005\\\\006\\\\a\\\\b\"..." ++ " = \\(unsigned char \\*\\) \"\\\\1\\\\2\\\\3\\\\4\\\\5\\\\6\\\\a\\\\b\"..." + gdb_test "p &ctable1\[1*8\]" \ +- " = \\(unsigned char \\*\\) \"\\\\b\\\\t\\\\n\\\\v\\\\f\\\\r\\\\016\\\\017\"..." ++ " = \\(unsigned char \\*\\) \"\\\\b\\\\t\\\\n\\\\v\\\\f\\\\r\\\\16\\\\17\"..." + gdb_test "p &ctable1\[2*8\]" \ +- " = \\(unsigned char \\*\\) \"\\\\020\\\\021\\\\022\\\\023\\\\024\\\\025\\\\026\\\\027\"..." ++ " = \\(unsigned char \\*\\) \"\\\\20\\\\21\\\\22\\\\23\\\\24\\\\25\\\\26\\\\27\"..." + gdb_test "p &ctable1\[3*8\]" \ +- " = \\(unsigned char \\*\\) \"\\\\030\\\\031\\\\032\\\\033\\\\034\\\\035\\\\036\\\\037\"..." ++ " = \\(unsigned char \\*\\) \"\\\\30\\\\31\\\\32\\\\33\\\\34\\\\35\\\\36\\\\37\"..." + gdb_test "p &ctable1\[4*8\]" \ + " = \\(unsigned char \\*\\) \" !\\\\\"#\\\$%&'\"..." + gdb_test "p &ctable1\[5*8\]" \ +@@ -622,7 +622,7 @@ proc test_print_string_constants {} { + set timeout 60; + + gdb_test "p \"a string\"" " = \"a string\"" +- gdb_test "p \"embedded \\000 null\"" " = \"embedded \\\\000 null\"" ++ gdb_test "p \"embedded \\000 null\"" " = \"embedded \\\\0 null\"" + gdb_test "p \"abcd\"\[2\]" " = 99 'c'" + gdb_test "p sizeof (\"abcdef\")" " = 7" + gdb_test "ptype \"foo\"" " = char \\\[4\\\]" +diff --git a/gdb/testsuite/gdb.base/return-nodebug.c b/gdb/testsuite/gdb.base/return-nodebug.c +new file mode 100644 +index 0000000..e1211b3 +--- /dev/null ++++ b/gdb/testsuite/gdb.base/return-nodebug.c +@@ -0,0 +1,49 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2009 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++#include ++ ++static TYPE ++init (void) ++{ ++ return 0; ++} ++ ++static TYPE ++func (void) ++{ ++ return 31; ++} ++ ++static void ++marker (void) ++{ ++} ++ ++int ++main (void) ++{ ++ /* Preinitialize registers to 0 to avoid false PASS by leftover garbage. */ ++ init (); ++ ++ printf ("result=" FORMAT "\n", CAST func ()); ++ ++ /* Cannot `next' with no debug info. */ ++ marker (); ++ ++ return 0; ++} +diff --git a/gdb/testsuite/gdb.base/return-nodebug.exp b/gdb/testsuite/gdb.base/return-nodebug.exp +new file mode 100644 +index 0000000..6f32aa9 +--- /dev/null ++++ b/gdb/testsuite/gdb.base/return-nodebug.exp +@@ -0,0 +1,54 @@ ++# Copyright (C) 2009 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++proc do_test {type} { ++ set typenospace [string map {{ } -} $type] ++ ++ global pf_prefix ++ set old_prefix $pf_prefix ++ lappend pf_prefix "$typenospace:" ++ ++ if {[runto "func"]} { ++ # Test return from a function with no debug info (symbol; still it may ++ # have a minimal-symbol) if it does not crash. ++ gdb_test "return -1" "#0 .* main \\(.*" \ ++ "return from function with no debug info" \ ++ "Make selected stack frame return now\\? \\(y or n\\) " "y" ++ ++ # And if it returned the full width of the result. ++ gdb_test "adv marker" "\r\nresult=-1\r\n.* in marker \\(.*" \ ++ "full width of the returned result" ++ } ++ ++ set pf_prefix $old_prefix ++} ++ ++foreach case {{{signed char} %d (int)} \ ++ {{short} %d (int)} \ ++ {{int} %d} \ ++ {{long} %ld} \ ++ {{long long} %lld}} { ++ set type [lindex $case 0] ++ set format [lindex $case 1] ++ set cast [lindex $case 2] ++ ++ set typeesc [string map {{ } {\ }} $type] ++ set typenospace [string map {{ } -} $type] ++ ++ if {[prepare_for_testing return-nodebug.exp "return-nodebug-$typenospace" "return-nodebug.c" \ ++ [list "additional_flags=-DFORMAT=\"$format\" -DTYPE=$typeesc -DCAST=$cast"]] == 0} { ++ do_test $type ++ } ++} +diff --git a/gdb/testsuite/gdb.base/setvar.exp b/gdb/testsuite/gdb.base/setvar.exp +index 2350a33..3be8424 100644 +--- a/gdb/testsuite/gdb.base/setvar.exp ++++ b/gdb/testsuite/gdb.base/setvar.exp +@@ -121,7 +121,7 @@ proc test_set { args } { + # + + test_set "set variable v_char=0" "print v_char" ".\[0-9\]* = 0 \'.0\'" "set variable char=0" +-test_set "set variable v_char=1" "print v_char" ".\[0-9\]* = 1 \'.001\'" "set variable char=1" ++test_set "set variable v_char=1" "print v_char" ".\[0-9\]* = 1 \'.1\'" "set variable char=1" + test_set "set variable v_char=7" "print v_char" ".\[0-9\]* = 7 \'.a\'" "set variable char=7 (Bel)" + test_set "set variable v_char=32" "print v_char" ".\[0-9\]* = 32 \' \'" "set variable char=32 (SPC)" + test_set "set variable v_char=65" "print v_char" ".\[0-9\]* = 65 \'A\'" "set variable char=65 ('A')" +@@ -132,7 +132,7 @@ test_set "set variable v_char=127" "print v_char" ".\[0-9\]* = 127 \'.177\'" + # test "set variable" for type "signed char" + # + test_set "set variable v_char=0" "print v_signed_char" ".\[0-9\]* = 0 \'.0\'" "set variable signed char=0" +-test_set "set variable v_signed_char=1" "print v_signed_char" ".\[0-9\]* = 1 \'.001\'" "set variable signed char=1" ++test_set "set variable v_signed_char=1" "print v_signed_char" ".\[0-9\]* = 1 \'.1\'" "set variable signed char=1" + test_set "set variable v_signed_char=7" "print v_signed_char" ".\[0-9\]* = 7 \'.a\'" "set variable signed char=7 (Bel)" + test_set "set variable v_signed_char=32" "print v_signed_char" ".\[0-9\]* = 32 \' \'" "set variable signed char=32 (SPC)" + test_set "set variable v_signed_char=65" "print v_signed_char" ".\[0-9\]* = 65 \'A\'" "set variable signed char=65 ('A')" +@@ -151,7 +151,7 @@ gdb_test "print v_signed_char" ".\[0-9\]* = -1 \'.377\'" \ + # test "set variable" for type "unsigned char" + # + test_set "set variable v_unsigned_char=0" "print v_unsigned_char" ".\[0-9\]* = 0 \'.0\'" "set variable unsigned char=0" +-test_set "set variable v_unsigned_char=1" "print v_unsigned_char" ".\[0-9\]* = 1 \'.001\'" "set variable unsigned char=1" ++test_set "set variable v_unsigned_char=1" "print v_unsigned_char" ".\[0-9\]* = 1 \'.1\'" "set variable unsigned char=1" + test_set "set variable v_unsigned_char=7" "print v_unsigned_char" ".\[0-9\]* = 7 \'.a\'" "set variable unsigned char=7 (Bel)" + test_set "set variable v_unsigned_char=32" "print v_unsigned_char" ".\[0-9\]* = 32 \' \'" "set variable unsigned char=32 (SPC)" + test_set "set variable v_unsigned_char=65" "print v_unsigned_char" ".\[0-9\]* = 65 \'A\'" "set variable unsigned char=65 ('A')" +diff --git a/gdb/testsuite/gdb.base/store.exp b/gdb/testsuite/gdb.base/store.exp +index 963bb19..feab6bd 100644 +--- a/gdb/testsuite/gdb.base/store.exp ++++ b/gdb/testsuite/gdb.base/store.exp +@@ -74,7 +74,7 @@ proc check_set { t l r new add } { + "${prefix}; print incremented l, expecting ${add}" + } + +-check_set "charest" "-1 .*" "-2 .*" "4 ..004." "2 ..002." ++check_set "charest" "-1 .*" "-2 .*" "4 ..4." "2 ..2." + check_set "short" "-1" "-2" "4" "2" + check_set "int" "-1" "-2" "4" "2" + check_set "long" "-1" "-2" "4" "2" +@@ -102,7 +102,7 @@ proc up_set { t l r new } { + "${prefix}; print new l, expecting ${new}" + } + +-up_set "charest" "-1 .*" "-2 .*" "4 ..004." ++up_set "charest" "-1 .*" "-2 .*" "4 ..4." + up_set "short" "-1" "-2" "4" + up_set "int" "-1" "-2" "4" + up_set "long" "-1" "-2" "4" +diff --git a/gdb/testsuite/gdb.base/valgrind-attach.c b/gdb/testsuite/gdb.base/valgrind-attach.c +new file mode 100644 +index 0000000..84b57db +--- /dev/null ++++ b/gdb/testsuite/gdb.base/valgrind-attach.c +@@ -0,0 +1,28 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2009 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++#include ++ ++int ++main (void) ++{ ++ int *a = malloc (1); ++ ++ a[10] = 0; /* crash-here */ ++ ++ return 0; ++} +diff --git a/gdb/testsuite/gdb.base/valgrind-attach.exp b/gdb/testsuite/gdb.base/valgrind-attach.exp +new file mode 100644 +index 0000000..1f9b26e +--- /dev/null ++++ b/gdb/testsuite/gdb.base/valgrind-attach.exp +@@ -0,0 +1,94 @@ ++# Copyright 2009 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++set testfile valgrind-attach ++set shfile ${testfile}.sh ++set srcfile ${testfile}.c ++set binfile ${objdir}/${subdir}/${testfile} ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { ++ untested "Couldn't compile test program" ++ return -1 ++} ++ ++gdb_exit ++gdb_stop_suppressing_tests; ++ ++set VALGRIND "valgrind" ++ ++# Syntax for ${shfile} is: ++set VALGRIND_SPAWN "sh ${srcdir}/${subdir}/${shfile} $binfile $VALGRIND $GDB $INTERNAL_GDBFLAGS $GDBFLAGS [host_info gdb_opts]" ++ ++set test "spawn valgrind" ++verbose "Spawning $VALGRIND_SPAWN" ++ ++if [info exists gdb_spawn_id] { ++ fail $test ++ return -1 ++} ++ ++if ![is_remote host] { ++ if { [which $VALGRIND] == 0 } then { ++ untested "Couldn't find $VALGRIND" ++ return -1 ++ } ++} ++set res [remote_spawn host "$VALGRIND_SPAWN"] ++if { $res < 0 || $res == "" } { ++ perror "Spawning $VALGRIND_SPAWN failed." ++ return -1 ++} ++set gdb_spawn_id -1; ++ ++gdb_expect { ++ -re "---- Attach to debugger \\? --- \\\[Return/N/n/Y/y/C/c\\\] ---- $" { ++ pass $test ++ } ++ eof { ++ perror "(eof) $VALGRIND never initialized" ++ remote_close host ++ return -1 ++ } ++ timeout { ++ perror "(timeout) $VALGRIND never initialized" ++ remote_close host ++ return -1 ++ } ++} ++send_gdb "y\n" ++ ++set test "spawn gdb" ++set test2 "crash line caught" ++gdb_expect { ++ -re "starting debugger with cmd:.* in main .* crash-here .*\[\r\n\]$gdb_prompt $" { ++ pass $test ++ pass $test2 ++ } ++ -re "starting debugger with cmd:.*\[\r\n\]$gdb_prompt $" { ++ pass $test ++ fail $test2 ++ } ++ eof { ++ perror "(eof) $GDB never initialized" ++ remote_close host ++ return -1 ++ } ++ timeout { ++ perror "(timeout) $GDB never initialized" ++ remote_close host ++ return -1 ++ } ++} ++ ++remote_close host +diff --git a/gdb/testsuite/gdb.base/valgrind-attach.sh b/gdb/testsuite/gdb.base/valgrind-attach.sh +new file mode 100755 +index 0000000..f02c6f7 +--- /dev/null ++++ b/gdb/testsuite/gdb.base/valgrind-attach.sh +@@ -0,0 +1,20 @@ ++#! /bin/sh ++ ++# Copyright 2009 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++BINFILE="$1"; shift ++VALGRIND="$1"; shift ++"$VALGRIND" --db-attach=yes --db-command="$* %f %p" "$BINFILE" +diff --git a/gdb/testsuite/gdb.base/vla-overflow.c b/gdb/testsuite/gdb.base/vla-overflow.c +new file mode 100644 +index 0000000..c5d5ee0 +--- /dev/null ++++ b/gdb/testsuite/gdb.base/vla-overflow.c +@@ -0,0 +1,30 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2008 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++#include ++ ++int ++main (int argc, char **argv) ++{ ++ int array[argc]; ++ ++ array[0] = array[0]; ++ ++ abort (); ++ ++ return 0; ++} +diff --git a/gdb/testsuite/gdb.base/vla-overflow.exp b/gdb/testsuite/gdb.base/vla-overflow.exp +new file mode 100644 +index 0000000..7203a48 +--- /dev/null ++++ b/gdb/testsuite/gdb.base/vla-overflow.exp +@@ -0,0 +1,108 @@ ++# Copyright 2008 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++# We could crash in: ++# #0 block_linkage_function (bl=0x0) at ../../gdb/block.c:69 ++# #1 in dwarf_block_get_frame_base (...) at ../../gdb/dwarf2block.c:97 ++# 97 framefunc = block_linkage_function (get_frame_block (frame, NULL)); ++# #2 in execute_stack_op (...) at ../../gdb/dwarf2expr.c:496 ++# #3 in dwarf_block_exec_core () at ../../gdb/dwarf2block.c:156 ++# #4 dwarf_block_exec (...) at ../../gdb/dwarf2block.c:206 ++# #5 in range_type_count_bound_internal (...) at ../../gdb/gdbtypes.c:1430 ++# #6 in create_array_type (...) at ../../gdb/gdbtypes.c:840 ++# ... ++# #21 in psymtab_to_symtab (...) at ../../gdb/symfile.c:292 ++# ... ++# #29 in backtrace_command_1 () at ../../gdb/stack.c:1273 ++ ++set testfile vla-overflow ++set shfile ${objdir}/${subdir}/${testfile}-gdb.sh ++set srcfile ${testfile}.c ++set binfile ${objdir}/${subdir}/${testfile} ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { ++ untested "Couldn't compile test program" ++ return -1 ++} ++ ++set f [open "|getconf PAGESIZE" "r"] ++gets $f pagesize ++close $f ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++set pid_of_gdb [exp_pid -i [board_info host fileid]] ++ ++if { [runto_main] < 0 } { ++ untested vla-overflow ++ return -1 ++} ++ ++# Get the GDB memory size when we stay at main. ++ ++proc memory_v_pages_get {} { ++ global pid_of_gdb pagesize ++ set fd [open "/proc/$pid_of_gdb/statm"] ++ gets $fd line ++ close $fd ++ # number of pages of virtual memory ++ scan $line "%d" drs ++ return $drs ++} ++ ++set pages_found [memory_v_pages_get] ++ ++set mb_reserve 10 ++verbose -log "pages_found = $pages_found, mb_reserve = $mb_reserve" ++set kb_found [expr $pages_found * $pagesize / 1024] ++set kb_permit [expr $kb_found + 1 * 1024 + $mb_reserve * 1024] ++verbose -log "kb_found = $kb_found, kb_permit = $kb_permit" ++ ++# Create the ulimit wrapper. ++set f [open $shfile "w"] ++puts $f "#! /bin/sh" ++puts $f "ulimit -v $kb_permit" ++puts $f "exec $GDB \"\$@\"" ++close $f ++remote_exec host "chmod +x $shfile" ++ ++gdb_exit ++set GDBold $GDB ++set GDB "$shfile" ++gdb_start ++set GDB $GDBold ++ ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++set pid_of_gdb [exp_pid -i [board_info host fileid]] ++ ++# Check the size again after the second run. ++# We must not stop in main as it would cache `array' and never crash later. ++ ++gdb_run_cmd ++ ++verbose -log "kb_found before abort() = [expr [memory_v_pages_get] * $pagesize / 1024]" ++ ++gdb_test "" "Program received signal SIGABRT, Aborted..*" "Enter abort()" ++ ++verbose -log "kb_found in abort() = [expr [memory_v_pages_get] * $pagesize / 1024]" ++ ++# `abort' can get expressed as `*__GI_abort'. ++gdb_test "bt" "in \[^ \]*abort \\(.* in main \\(.*" "Backtrace after abort()" ++ ++verbose -log "kb_found in bt after abort() = [expr [memory_v_pages_get] * $pagesize / 1024]" +diff --git a/gdb/testsuite/gdb.base/vla.c b/gdb/testsuite/gdb.base/vla.c +new file mode 100644 +index 0000000..e1f3ed1 +--- /dev/null ++++ b/gdb/testsuite/gdb.base/vla.c +@@ -0,0 +1,55 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2008 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++#include ++ ++void ++marker (void) ++{ ++} ++ ++void ++bar (char *a, char *b, char *c, int size) ++{ ++ memset (a, '1', size); ++ memset (b, '2', size); ++ memset (c, '3', 48); ++} ++ ++void ++foo (int size) ++{ ++ char temp1[size]; ++ char temp3[48]; ++ ++ temp1[size - 1] = '\0'; ++ { ++ char temp2[size]; ++ ++ bar (temp1, temp2, temp3, size); ++ ++ marker (); /* break-here */ ++ } ++} ++ ++int ++main (void) ++{ ++ foo (26); ++ foo (78); ++ return 0; ++} +diff --git a/gdb/testsuite/gdb.base/vla.exp b/gdb/testsuite/gdb.base/vla.exp +new file mode 100644 +index 0000000..5da7378 +--- /dev/null ++++ b/gdb/testsuite/gdb.base/vla.exp +@@ -0,0 +1,62 @@ ++# Copyright 2008 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++set testfile vla ++set srcfile ${testfile}.c ++set binfile ${objdir}/${subdir}/${testfile} ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { ++ untested "Couldn't compile test program" ++ return -1 ++} ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++if ![runto_main] { ++ untested vla ++ return -1 ++} ++ ++gdb_breakpoint [gdb_get_line_number "break-here"] ++ ++gdb_continue_to_breakpoint "break-here" ++ ++gdb_test "whatis temp1" "type = char \\\[variable\\\]" "first: whatis temp1" ++gdb_test "whatis temp2" "type = char \\\[variable\\\]" "first: whatis temp2" ++gdb_test "whatis temp3" "type = char \\\[48\\\]" "first: whatis temp3" ++ ++gdb_test "ptype temp1" "type = char \\\[26\\\]" "first: ptype temp1" ++gdb_test "ptype temp2" "type = char \\\[26\\\]" "first: ptype temp2" ++gdb_test "ptype temp3" "type = char \\\[48\\\]" "first: ptype temp3" ++ ++gdb_test "p temp1" " = '1' " "first: print temp1" ++gdb_test "p temp2" " = '2' " "first: print temp2" ++gdb_test "p temp3" " = '3' " "first: print temp3" ++ ++gdb_continue_to_breakpoint "break-here" ++ ++gdb_test "whatis temp1" "type = char \\\[variable\\\]" "second: whatis temp1" ++gdb_test "whatis temp2" "type = char \\\[variable\\\]" "second: whatis temp2" ++gdb_test "whatis temp3" "type = char \\\[48\\\]" "second: whatis temp3" ++ ++gdb_test "ptype temp1" "type = char \\\[78\\\]" "second: ptype temp1" ++gdb_test "ptype temp2" "type = char \\\[78\\\]" "second: ptype temp2" ++gdb_test "ptype temp3" "type = char \\\[48\\\]" "second: ptype temp3" ++ ++gdb_test "p temp1" " = '1' " "second: print temp1" ++gdb_test "p temp2" " = '2' " "second: print temp2" ++gdb_test "p temp3" " = '3' " "second: print temp3" +diff --git a/gdb/testsuite/gdb.cp/Makefile.in b/gdb/testsuite/gdb.cp/Makefile.in +index 1787ad5..391bfc2 100644 +--- a/gdb/testsuite/gdb.cp/Makefile.in ++++ b/gdb/testsuite/gdb.cp/Makefile.in +@@ -4,7 +4,7 @@ srcdir = @srcdir@ + EXECUTABLES = ambiguous annota2 anon-union cplusfuncs cttiadd \ + derivation inherit local member-ptr method misc \ + overload ovldbreak ref-typ ref-typ2 templates userdef virtfunc namespace \ +- ref-types ref-params method2 pr9594 ++ ref-types ref-params method2 pr9594 gdb2495 + + all info install-info dvi install uninstall installcheck check: + @echo "Nothing to be done for $@..." +diff --git a/gdb/testsuite/gdb.cp/abstract-origin.cc b/gdb/testsuite/gdb.cp/abstract-origin.cc +new file mode 100644 +index 0000000..e2de3fb +--- /dev/null ++++ b/gdb/testsuite/gdb.cp/abstract-origin.cc +@@ -0,0 +1,42 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2008 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ */ ++ ++extern void f (int *); ++ ++class A ++{ ++public: ++ A(int i); ++}; ++ ++A::A(int i) ++{ ++ static int *problem = new int(i); ++ f (problem); /* break-here */ ++} ++ ++void f (int *) ++{ ++} ++ ++int ++main (void) ++{ ++ A a(42); ++ return 0; ++} +diff --git a/gdb/testsuite/gdb.cp/abstract-origin.exp b/gdb/testsuite/gdb.cp/abstract-origin.exp +new file mode 100644 +index 0000000..92cc23c +--- /dev/null ++++ b/gdb/testsuite/gdb.cp/abstract-origin.exp +@@ -0,0 +1,40 @@ ++# Copyright 2008 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++set testfile abstract-origin ++set srcfile ${testfile}.cc ++set binfile ${objdir}/${subdir}/${testfile} ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug c++}] != "" } { ++ untested "Couldn't compile test program" ++ return -1 ++} ++ ++# Get things started. ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++if ![runto_main] { ++ untested abstract-origin ++ return -1 ++} ++ ++gdb_breakpoint [gdb_get_line_number "break-here"] ++gdb_continue_to_breakpoint "break-here" ++ ++# The Bug was: No symbol "problem" in current context. ++gdb_test "p problem" " = \\(int \\*\\) 0x.*" +diff --git a/gdb/testsuite/gdb.cp/cplusfuncs.cc b/gdb/testsuite/gdb.cp/cplusfuncs.cc +index 7f033d6..1a50a32 100644 +--- a/gdb/testsuite/gdb.cp/cplusfuncs.cc ++++ b/gdb/testsuite/gdb.cp/cplusfuncs.cc +@@ -191,6 +191,12 @@ char * dm_type_char_star (char * p) { return p; } + int dm_type_foo_ref (foo & foo) { return foo.ifoo; } + int * dm_type_int_star (int * p) { return p; } + long * dm_type_long_star (long * p) { return p; } ++int dm_type_short (short i) { return i; } ++int dm_type_long (long i) { return i; } + int dm_type_unsigned_int (unsigned int i) { return i; } ++int dm_type_unsigned_short (unsigned short i) { return i; } ++int dm_type_unsigned_long (unsigned long i) { return i; } + int dm_type_void (void) { return 0; } + void * dm_type_void_star (void * p) { return p; } ++typedef int myint; ++int dm_type_typedef (myint i) { return i; } +diff --git a/gdb/testsuite/gdb.cp/cplusfuncs.exp b/gdb/testsuite/gdb.cp/cplusfuncs.exp +index 5e08768..8c8e038 100644 +--- a/gdb/testsuite/gdb.cp/cplusfuncs.exp ++++ b/gdb/testsuite/gdb.cp/cplusfuncs.exp +@@ -66,9 +66,25 @@ set dm_type_unsigned_int "unsigned" + set dm_type_void "" + set dm_type_void_star "void*" + ++# Some other vagaries of GDB's type printing machinery. The integer types ++# may have unsigned before or after their length, and may have "int" ++# appended. The char* conversion operator may have name "char*" even if ++# the type is "char *", because the name comes from the debug information ++# and the type from GDB. Function types may not see through typedefs. ++ ++set dm_type_short "short" ++set dm_type_long "long" ++set dm_type_unsigned_short "unsigned short" ++set dm_type_unsigned_long "unsigned long" ++set dm_operator_char_star "char*" ++set dm_operator_char_star_quoted "char\\*" ++set dm_type_typedef 0 ++ + proc probe_demangler { } { + global gdb_prompt + global dm_operator_comma ++ global dm_operator_char_star ++ global dm_operator_char_star_quoted + global dm_type_char_star + global dm_type_char_star_quoted + global dm_type_foo_ref +@@ -77,6 +93,11 @@ proc probe_demangler { } { + global dm_type_unsigned_int + global dm_type_void + global dm_type_void_star ++ global dm_type_short ++ global dm_type_unsigned_short ++ global dm_type_long ++ global dm_type_unsigned_long ++ global dm_type_typedef + + send_gdb "print &'foo::operator,(foo&)'\n" + gdb_expect { +@@ -97,6 +118,26 @@ proc probe_demangler { } { + } + } + ++ send_gdb "print &'foo::operator char*()'\n" ++ gdb_expect { ++ -re ".*foo::operator char \\*\\(void\\).*\r\n$gdb_prompt $" { ++ # v2 demangler or GDB type printer ++ set dm_operator_char_star "char *" ++ set dm_operator_char_star_quoted "char \\*" ++ pass "detect dm_operator_char_star" ++ } ++ -re ".*foo::operator char\\*\\(\\).*\r\n$gdb_prompt $" { ++ # v3 demangler ++ pass "detect dm_operator_char_star" ++ } ++ -re ".*$gdb_prompt $" { ++ fail "detect dm_operator_char_star" ++ } ++ timeout { ++ fail "detect dm_operator_char_star" ++ } ++ } ++ + send_gdb "print &'dm_type_char_star'\n" + gdb_expect { + -re ".*dm_type_char_star\\(char \\*\\).*\r\n$gdb_prompt $" { +@@ -166,6 +207,11 @@ proc probe_demangler { } { + # v3 demangler + pass "detect dm_type_long_star" + } ++ -re ".*dm_type_long_star\\(long int \\*\\).*\r\n$gdb_prompt $" { ++ # GCC v3 and GDB's type printer ++ set dm_type_long_star "long int *" ++ pass "detect dm_type_long_star" ++ } + -re ".*$gdb_prompt $" { + fail "detect dm_type_long_star" + } +@@ -230,6 +276,101 @@ proc probe_demangler { } { + fail "detect dm_type_void_star (timeout)" + } + } ++ ++ send_gdb "print &'dm_type_short'\n" ++ gdb_expect { ++ -re ".*dm_type_short\\(short\\).*\r\n$gdb_prompt $" { ++ # v2 and v3 demanglers ++ pass "detect dm_type_short" ++ } ++ -re ".*dm_type_short\\(short int\\).*\r\n$gdb_prompt $" { ++ # GDB type printer ++ set dm_type_short "short int" ++ pass "detect dm_type_short" ++ } ++ -re ".*$gdb_prompt $" { ++ fail "detect dm_type_short" ++ } ++ timeout { ++ fail "detect dm_type_short (timeout)" ++ } ++ } ++ ++ send_gdb "print &'dm_type_unsigned_short'\n" ++ gdb_expect { ++ -re ".*dm_type_unsigned_short\\(unsigned short\\).*\r\n$gdb_prompt $" { ++ # v2 and v3 demanglers ++ pass "detect dm_type_unsigned_short" ++ } ++ -re ".*dm_type_unsigned_short\\(short unsigned int\\).*\r\n$gdb_prompt $" { ++ # GDB type printer ++ set dm_type_unsigned_short "short unsigned int" ++ pass "detect dm_type_unsigned_short" ++ } ++ -re ".*$gdb_prompt $" { ++ fail "detect dm_type_unsigned_short" ++ } ++ timeout { ++ fail "detect dm_type_unsigned_short (timeout)" ++ } ++ } ++ ++ send_gdb "print &'dm_type_long'\n" ++ gdb_expect { ++ -re ".*dm_type_long\\(long\\).*\r\n$gdb_prompt $" { ++ # v2 and v3 demanglers ++ pass "detect dm_type_long" ++ } ++ -re ".*dm_type_long\\(long int\\).*\r\n$gdb_prompt $" { ++ # GDB type printer ++ set dm_type_long "long int" ++ pass "detect dm_type_long" ++ } ++ -re ".*$gdb_prompt $" { ++ fail "detect dm_type_long" ++ } ++ timeout { ++ fail "detect dm_type_long (timeout)" ++ } ++ } ++ ++ send_gdb "print &'dm_type_unsigned_long'\n" ++ gdb_expect { ++ -re ".*dm_type_unsigned_long\\(unsigned long\\).*\r\n$gdb_prompt $" { ++ # v2 and v3 demanglers ++ pass "detect dm_type_unsigned_long" ++ } ++ -re ".*dm_type_unsigned_long\\(long unsigned int\\).*\r\n$gdb_prompt $" { ++ # GDB type printer ++ set dm_type_unsigned_long "long unsigned int" ++ pass "detect dm_type_unsigned_long" ++ } ++ -re ".*$gdb_prompt $" { ++ fail "detect dm_type_unsigned_long" ++ } ++ timeout { ++ fail "detect dm_type_unsigned_long (timeout)" ++ } ++ } ++ ++ send_gdb "print &'dm_type_typedef'\n" ++ gdb_expect { ++ -re ".*dm_type_typedef\\(int\\).*\r\n$gdb_prompt $" { ++ # v2 and v3 demanglers ++ pass "detect dm_type_typedef" ++ } ++ -re ".*dm_type_typedef\\(myint\\).*\r\n$gdb_prompt $" { ++ # GDB type printer ++ set dm_type_typedef 1 ++ pass "detect dm_type_typedef" ++ } ++ -re ".*$gdb_prompt $" { ++ fail "detect dm_type_typedef" ++ } ++ timeout { ++ fail "detect dm_type_typedef (timeout)" ++ } ++ } + } + + # +@@ -345,8 +486,9 @@ proc print_addr { name } { + + proc test_lookup_operator_functions {} { + global dm_operator_comma ++ global dm_operator_char_star + global dm_type_char_star +- global dm_type_char_star_quoted ++ global dm_operator_char_star_quoted + global dm_type_foo_ref + global dm_type_void + global dm_type_void_star +@@ -404,8 +546,8 @@ proc test_lookup_operator_functions {} { + + info_func "operator int(" "int foo::operator int($dm_type_void);" + info_func "operator()(" "void foo::operator()($dm_type_foo_ref);" +- info_func "operator $dm_type_char_star_quoted\(" \ +- "char *foo::operator $dm_type_char_star\($dm_type_void);" ++ info_func "operator $dm_operator_char_star_quoted\(" \ ++ "char *foo::operator $dm_operator_char_star\($dm_type_void);" + + } + +@@ -420,6 +562,7 @@ proc test_paddr_operator_functions {} { + global dm_type_unsigned_int + global dm_type_void + global dm_type_void_star ++ global dm_operator_char_star + + print_addr "foo::operator*($dm_type_foo_ref)" + print_addr "foo::operator%($dm_type_foo_ref)" +@@ -470,7 +613,7 @@ proc test_paddr_operator_functions {} { + } + + print_addr "foo::operator int($dm_type_void)" +- print_addr "foo::operator $dm_type_char_star\($dm_type_void)" ++ print_addr "foo::operator $dm_operator_char_star\($dm_type_void)" + } + + # +@@ -480,17 +623,21 @@ proc test_paddr_operator_functions {} { + proc test_paddr_overloaded_functions {} { + global dm_type_unsigned_int + global dm_type_void ++ global dm_type_short ++ global dm_type_unsigned_short ++ global dm_type_long ++ global dm_type_unsigned_long + + print_addr "overload1arg($dm_type_void)" + print_addr "overload1arg(char)" + print_addr "overload1arg(signed char)" + print_addr "overload1arg(unsigned char)" +- print_addr "overload1arg(short)" +- print_addr "overload1arg(unsigned short)" ++ print_addr "overload1arg($dm_type_short)" ++ print_addr "overload1arg($dm_type_unsigned_short)" + print_addr "overload1arg(int)" + print_addr "overload1arg($dm_type_unsigned_int)" +- print_addr "overload1arg(long)" +- print_addr "overload1arg(unsigned long)" ++ print_addr "overload1arg($dm_type_long)" ++ print_addr "overload1arg($dm_type_unsigned_long)" + print_addr "overload1arg(float)" + print_addr "overload1arg(double)" + +@@ -513,17 +660,31 @@ proc test_paddr_hairy_functions {} { + global dm_type_char_star + global dm_type_int_star + global dm_type_long_star ++ global dm_type_typedef + + print_addr_2 "hairyfunc1" "hairyfunc1(int)" +- print_addr_2 "hairyfunc2" "hairyfunc2(int (*)($dm_type_char_star))" +- print_addr_2 "hairyfunc3" "hairyfunc3(int (*)(short (*)($dm_type_long_star)))" +- print_addr_2 "hairyfunc4" "hairyfunc4(int (*)(short (*)($dm_type_char_star)))" +- +- # gdb-gnats bug gdb/19: +- # "gdb v3 demangler fails on hairyfunc5 hairyfunc6 hairyfunc7" +- print_addr_2_kfail "hairyfunc5" "hairyfunc5(int (*(*)($dm_type_char_star))(long))" "hairyfunc5(int (*)(long) (*)(char*))" "gdb/19" +- print_addr_2_kfail "hairyfunc6" "hairyfunc6(int (*(*)($dm_type_int_star))(long))" "hairyfunc6(int (*)(long) (*)(int*))" "gdb/19" +- print_addr_2_kfail "hairyfunc7" "hairyfunc7(int (*(*)(int (*)($dm_type_char_star)))(long))" "hairyfunc7(int (*)(long) (*)(int (*)(char*)))" "gdb/19" ++ ++ if {$dm_type_typedef == 0} { ++ print_addr_2 "hairyfunc2" "hairyfunc2(int (*)($dm_type_char_star))" ++ print_addr_2 "hairyfunc3" "hairyfunc3(int (*)(short (*)($dm_type_long_star)))" ++ print_addr_2 "hairyfunc4" "hairyfunc4(int (*)(short (*)($dm_type_char_star)))" ++ ++ # gdb-gnats bug gdb/19: ++ # "gdb v3 demangler fails on hairyfunc5 hairyfunc6 hairyfunc7" ++ print_addr_2_kfail "hairyfunc5" "hairyfunc5(int (*(*)($dm_type_char_star))(long))" "hairyfunc5(int (*)(long) (*)(char*))" "gdb/19" ++ print_addr_2_kfail "hairyfunc6" "hairyfunc6(int (*(*)($dm_type_int_star))(long))" "hairyfunc6(int (*)(long) (*)(int*))" "gdb/19" ++ print_addr_2_kfail "hairyfunc7" "hairyfunc7(int (*(*)(int (*)($dm_type_char_star)))(long))" "hairyfunc7(int (*)(long) (*)(int (*)(char*)))" "gdb/19" ++ } else { ++ print_addr_2 "hairyfunc2" "hairyfunc2(PFPc_i)" ++ print_addr_2 "hairyfunc3" "hairyfunc3(PFPFPl_s_i)" ++ print_addr_2 "hairyfunc4" "hairyfunc4(PFPFPc_s_i)" ++ ++ # gdb-gnats bug gdb/19: ++ # "gdb v3 demangler fails on hairyfunc5 hairyfunc6 hairyfunc7" ++ print_addr_2 "hairyfunc5" "hairyfunc5(PFPc_PFl_i)" ++ print_addr_2 "hairyfunc6" "hairyfunc6(PFPi_PFl_i)" ++ print_addr_2 "hairyfunc7" "hairyfunc7(PFPFPc_i_PFl_i)" ++ } + } + + proc do_tests {} { +diff --git a/gdb/testsuite/gdb.cp/expand-sals.cc b/gdb/testsuite/gdb.cp/expand-sals.cc +new file mode 100644 +index 0000000..6169a05 +--- /dev/null ++++ b/gdb/testsuite/gdb.cp/expand-sals.cc +@@ -0,0 +1,53 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright (C) 2009 Free Software Foundation, Inc. ++ ++ This file is part of GDB. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++int ++func () ++{ ++ return 42; /* func-line */ ++} ++ ++volatile int global_x; ++ ++class A ++{ ++public: ++ A () ++ { ++ global_x = func (); /* caller-line */ ++ } ++}; ++ ++/* class B is here just to make the `func' calling line above having multiple ++ instances - multiple locations. Template cannot be used as its instances ++ would have different function names which get discarded by GDB ++ expand_line_sal_maybe. */ ++ ++class B : public A ++{ ++}; ++ ++int ++main (void) ++{ ++ A a; ++ B b; ++ ++ return 0; /* exit-line */ ++} +diff --git a/gdb/testsuite/gdb.cp/expand-sals.exp b/gdb/testsuite/gdb.cp/expand-sals.exp +new file mode 100644 +index 0000000..a2631fb +--- /dev/null ++++ b/gdb/testsuite/gdb.cp/expand-sals.exp +@@ -0,0 +1,100 @@ ++# Copyright 2009 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++if { [skip_cplus_tests] } { continue } ++ ++set srcfile expand-sals.cc ++if { [prepare_for_testing expand-sals.exp expand-sals $srcfile {debug c++}] } { ++ return -1 ++} ++if ![runto_main] { ++ return -1 ++} ++ ++gdb_breakpoint [gdb_get_line_number "exit-line"] ++ ++gdb_breakpoint [gdb_get_line_number "func-line"] ++gdb_continue_to_breakpoint "func" ".*func-line.*" ++ ++gdb_test "up" "caller-line.*" ++ ++# PC should not be at the boundary of source lines to make the original bug ++# exploitable. ++ ++set test "p/x \$pc" ++set pc {} ++gdb_test_multiple $test $test { ++ -re "\\$\[0-9\]+ = (0x\[0-9a-f\]+)\r\n$gdb_prompt $" { ++ set pc $expect_out(1,string) ++ pass $test ++ } ++} ++ ++set test "info line" ++set end {} ++gdb_test_multiple $test $test { ++ -re "Line \[0-9\]+ of .* starts at address 0x\[0-9a-f\]+.* and ends at (0x\[0-9a-f\]+).*\\.\r\n$gdb_prompt $" { ++ set end $expect_out(1,string) ++ pass $test ++ } ++} ++ ++set test "caller line has trailing code" ++if {$pc != $end} { ++ pass $test ++} else { ++ fail $test ++} ++ ++# Original problem was an internal error here. Still sanity multiple locations ++# were found at this code place as otherwise this test would not test anything. ++set test "break" ++gdb_test_multiple $test $test { ++ -re "Breakpoint \[0-9\]+ at .*, line \[0-9\]+\\. \\(\[2-9\] locations\\)\r\n$gdb_prompt $" { ++ pass $test ++ } ++ -re "Breakpoint \[0-9\]+ at .*, line \[0-9\]+\\.\r\n$gdb_prompt $" { ++ # It just could not be decided if GDB is OK by this testcase. ++ setup_xfail *-*-* ++ fail $test ++ return 0 ++ } ++} ++ ++gdb_continue_to_breakpoint "caller" ".*caller-line.*" ++ ++# Test GDB caught this return call and not the next one through B::B() ++gdb_test "bt" \ ++ "#0 \[^\r\n\]* A \[^\r\n\]*\r\n#1 \[^\r\n\]* main \[^\r\n\]*" \ ++ "bt from A" ++ ++gdb_continue_to_breakpoint "next caller instance" ".*caller-line.*" ++ ++# Test that GDB caught now already A through B::B() in the other instance. ++# As discussed in GDB expand_line_sal_maybe it would more match the original ++# instance behavior to catch here the `func' breakpoint and catch the ++# multiple-locations breakpoint only during the call return. This is not the ++# case, expecting here to catch the breakpoint before the call happens. ++ ++gdb_test "bt" \ ++ "#0 \[^\r\n\]* A \[^\r\n\]*\r\n#1 \[^\r\n\]* B \[^\r\n\]*\r\n#2 \[^\r\n\]* main \[^\r\n\]*" \ ++ "bt from B before the call" ++ ++gdb_continue_to_breakpoint "next caller func" ".*func-line.*" ++ ++# Verify GDB really could not catch the originally intended point of the return ++# from func. ++ ++gdb_continue_to_breakpoint "uncaught return" ".*exit-line.*" +diff --git a/gdb/testsuite/gdb.cp/gdb1355.exp b/gdb/testsuite/gdb.cp/gdb1355.exp +index 77687a6..66d16cf 100644 +--- a/gdb/testsuite/gdb.cp/gdb1355.exp ++++ b/gdb/testsuite/gdb.cp/gdb1355.exp +@@ -68,11 +68,11 @@ set s_tail ".*" + + set f_i "${ws}int m_int;" + set f_c "${ws}char m_char;" +-set f_li "${ws}long int m_long_int;" ++set f_li "${ws}long m_long_int;" + set f_ui "${ws}unsigned int m_unsigned_int;" +-set f_lui "${ws}long unsigned int m_long_unsigned_int;" +-set f_si "${ws}short int m_short_int;" +-set f_sui "${ws}short unsigned int m_short_unsigned_int;" ++set f_lui "${ws}unsigned long m_long_unsigned_int;" ++set f_si "${ws}short m_short_int;" ++set f_sui "${ws}unsigned short m_short_unsigned_int;" + set f_uc "${ws}unsigned char m_unsigned_char;" + set f_f "${ws}float m_float;" + set f_d "${ws}double m_double;" +diff --git a/gdb/testsuite/gdb.cp/gdb2495.cc b/gdb/testsuite/gdb.cp/gdb2495.cc +new file mode 100644 +index 0000000..4df265f +--- /dev/null ++++ b/gdb/testsuite/gdb.cp/gdb2495.cc +@@ -0,0 +1,90 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2008 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ */ ++ ++#include ++#include ++ ++using namespace std; ++ ++class SimpleException ++{ ++ ++public: ++ ++ void raise_signal (int dummy) ++ { ++ if (dummy > 0) ++ raise(SIGABRT); ++ } ++ ++ int no_throw_function () ++ { ++ return 1; ++ } ++ ++ void throw_function () ++ { ++ throw 1; ++ } ++ ++ int throw_function_with_handler () ++ { ++ try ++ { ++ throw 1; ++ } ++ catch (...) ++ { ++ cout << "Handled" << endl; ++ } ++ ++ return 2; ++ } ++ ++ void call_throw_function_no_handler () ++ { ++ throw_function (); ++ } ++ ++ void call_throw_function_handler () ++ { ++ throw_function_with_handler (); ++ } ++}; ++SimpleException exceptions; ++ ++int ++main() ++{ ++ // Have to call all these functions ++ // so not optimized away. ++ exceptions.raise_signal (-1); ++ exceptions.no_throw_function (); ++ exceptions.throw_function_with_handler (); ++ exceptions.call_throw_function_handler (); ++ try ++ { ++ exceptions.throw_function (); ++ exceptions.call_throw_function_no_handler (); ++ } ++ catch (...) ++ { ++ } ++ return 0; ++} ++ +diff --git a/gdb/testsuite/gdb.cp/gdb2495.exp b/gdb/testsuite/gdb.cp/gdb2495.exp +new file mode 100644 +index 0000000..62c09c2 +--- /dev/null ++++ b/gdb/testsuite/gdb.cp/gdb2495.exp +@@ -0,0 +1,160 @@ ++# Copyright 2008 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++ ++# In gdb inferior function calls, if a C++ exception is raised in the ++# dummy-frame, and the exception handler is (normally, and expected to ++# be) out-of-frame, the default C++ handler will (wrongly) be called ++# in an inferior function call. ++# This is incorrect as an exception can normally and legally be handled ++# out-of-frame. The confines of the dummy frame prevent the unwinder ++# from finding the correct handler (or any handler, unless it is ++# in-frame). The default handler calls std::terminate. This will kill ++# the inferior. Assert that terminate should never be called in an ++# inferior function call. These tests test the functionality around ++# unwinding that sequence and also tests the flag behaviour gating this ++# functionality. ++ ++# This test is largley based off gdb.base/callfuncs.exp. ++ ++if $tracelevel then { ++ strace $tracelevel ++} ++ ++if { [skip_cplus_tests] } { continue } ++ ++set prms_id 2495 ++set bug_id 0 ++ ++set testfile "gdb2495" ++set srcfile ${testfile}.cc ++set binfile $objdir/$subdir/$testfile ++ ++# Create and source the file that provides information about the compiler ++# used to compile the test case. ++if [get_compiler_info ${binfile} "c++"] { ++ return -1 ++} ++ ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug c++}] != "" } { ++ untested gdb2495.exp ++ return -1 ++} ++ ++# Some targets can't do function calls, so don't even bother with this ++# test. ++if [target_info exists gdb,cannot_call_functions] { ++ setup_xfail "*-*-*" 2416 ++ fail "This target can not call functions" ++ continue ++} ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++if ![runto_main] then { ++ perror "couldn't run to main" ++ continue ++} ++ ++# See http://sources.redhat.com/gdb/bugs/2495 ++ ++# Test normal baseline behaviour. Call a function that ++# does not raise an exception ... ++gdb_test "p exceptions.no_throw_function()" " = 1" ++# And one that does but handles it in-frame ... ++gdb_test "p exceptions.throw_function_with_handler()" " = 2" ++# Both should return normally. ++ ++# Test basic unwind. Call a function that raises an exception but ++# does not handle it. It should be rewound ... ++gdb_test "p exceptions.throw_function()" \ ++ "The program being debugged entered a std::terminate call .*" \ ++ "Call a function that raises an exception without a handler." ++ ++# Make sure that after rewinding we are back at the call parent. ++gdb_test "bt" \ ++ "#0 main.*" \ ++ "bt after returning from a popped frame" ++ ++# Make sure the only breakpoint is the one set via the runto_main ++# call and that the std::terminate breakpoint has evaporated and ++# cleaned-up. ++gdb_test "info breakpoints" \ ++ "gdb.cp/gdb2495\.cc.*" ++ ++# Turn off this new behaviour ... ++send_gdb "set unwind-on-terminating-exception off\n" ++gdb_expect { ++ -re "$gdb_prompt $" {pass "set unwind-on-terminating-exception"} ++ timeout {fail "(timeout) set unwind-on-terminating-exception"} ++} ++ ++# Check that it is turned off ... ++gdb_test "show unwind-on-terminating-exception" \ ++ "exception is unhandled while in a call dummy is off.*" \ ++ "Turn off unwind on terminating exception flag" ++ ++# Check that the old behaviour is restored. ++gdb_test "p exceptions.throw_function()" \ ++ "The program being debugged stopped while in a function called .*" \ ++ "Call a function that raises an exception with unwinding off.." ++ ++ ++# Restart back at main ++if ![runto_main] then { ++ perror "couldn't run to main" ++ continue ++} ++ ++ ++# Check to see if our new behaviour alters the unwind signal ++# behaviour. It should not. Test both on and off states. ++ ++# Turn on unwind on signal behaviour ... ++send_gdb "set unwindonsignal on\n" ++gdb_expect { ++ -re "$gdb_prompt $" {pass "set unwindonsignal on"} ++ timeout {fail "(timeout) set unwindonsignal on"} ++} ++ ++# Check that it is turned on ... ++gdb_test "show unwindonsignal" \ ++ "signal is received while in a call dummy is on.*" \ ++ "Turn on unwind on signal" ++ ++# Check to see if new behaviour interferes with ++# normal signal handling in inferior function calls. ++gdb_test "p exceptions.raise_signal(1)" \ ++ "To change this behavior use \"set unwindonsignal off\".*" ++ ++# And reverse. Turn off ++send_gdb "set unwindonsignal off\n" ++gdb_expect { ++ -re "$gdb_prompt $" {pass "set unwindonsignal off"} ++ timeout {fail "(timeout) set unwindonsignal off"} ++} ++ ++# Check that it is turned off ... ++gdb_test "show unwindonsignal" \ ++ "signal is received while in a call dummy is off.*" \ ++ "Turn off unwind on signal" ++ ++# Check to see if new behaviour interferes with ++# normal signal handling in inferior function calls. ++gdb_test "p exceptions.raise_signal(1)" \ ++ "To change this behavior use \"set unwindonsignal on\".*" +diff --git a/gdb/testsuite/gdb.cp/member-ptr.cc b/gdb/testsuite/gdb.cp/member-ptr.cc +index 1dff70a..648b2af 100644 +--- a/gdb/testsuite/gdb.cp/member-ptr.cc ++++ b/gdb/testsuite/gdb.cp/member-ptr.cc +@@ -138,6 +138,7 @@ class Diamond : public Padding, public Left, public Right + { + public: + virtual int vget_base (); ++ int (*func_ptr) (int); + }; + + int Diamond::vget_base () +@@ -145,6 +146,12 @@ int Diamond::vget_base () + return this->Left::x + 2000; + } + ++int ++func (int x) ++{ ++ return 19 + x; ++} ++ + int main () + { + A a; +@@ -162,6 +169,7 @@ int main () + int (Diamond::*right_vpmf) (); + int (Base::*base_vpmf) (); + int Diamond::*diamond_pmi; ++ int (* Diamond::*diamond_pfunc_ptr) (int); + + PMI null_pmi; + PMF null_pmf; +@@ -179,6 +187,7 @@ int main () + + diamond.Left::x = 77; + diamond.Right::x = 88; ++ diamond.func_ptr = func; + + /* Some valid pointer to members from a base class. */ + left_pmf = (int (Diamond::*) ()) (int (Left::*) ()) (&Base::get_x); +@@ -193,11 +202,19 @@ int main () + /* A pointer to data member from a base class. */ + diamond_pmi = (int Diamond::*) (int Left::*) &Base::x; + ++ /* A pointer to data member, where the member is itself a pointer to ++ a function. */ ++ diamond_pfunc_ptr = (int (* Diamond::*) (int)) &Diamond::func_ptr; ++ + null_pmi = NULL; + null_pmf = NULL; + + pmi = NULL; /* Breakpoint 1 here. */ + ++ // Invalid (uses diamond_pfunc_ptr as a function): ++ // diamond.*diamond_pfunc_ptr (20); ++ (diamond.*diamond_pfunc_ptr) (20); ++ + k = (a.*pmf)(3); + + pmi = &A::jj; +diff --git a/gdb/testsuite/gdb.cp/member-ptr.exp b/gdb/testsuite/gdb.cp/member-ptr.exp +index b69d4ad..476711f 100644 +--- a/gdb/testsuite/gdb.cp/member-ptr.exp ++++ b/gdb/testsuite/gdb.cp/member-ptr.exp +@@ -390,6 +390,33 @@ gdb_test_multiple "print ((int) pmi) == ((char *) &a.j - (char *) & a)" $name { + } + } + ++# Check pointers to data members, which are themselves pointers to ++# functions. These behave like data members, not like pointers to ++# member functions. ++ ++gdb_test "ptype diamond_pfunc_ptr" \ ++ "type = int \\(\\*Diamond::\\*\\)\\(int\\)" ++ ++gdb_test "ptype diamond.*diamond_pfunc_ptr" \ ++ "type = int \\(\\*\\)\\(int\\)" ++ ++# This one is invalid; () binds more tightly than .*, so it tries to ++# call the member pointer as a normal pointer-to-function. ++ ++gdb_test "print diamond.*diamond_pfunc_ptr (20)" \ ++ "Invalid data type for function to be called." ++ ++# With parentheses, it is valid. ++ ++gdb_test "print (diamond.*diamond_pfunc_ptr) (20)" \ ++ "$vhn = 39" ++ ++# Make sure that we do not interpret this as either a member pointer ++# call or a member function call. ++ ++gdb_test "print diamond.func_ptr (20)" \ ++ "$vhn = 39" ++ + # ========================== + # pointer to member function + # ========================== +@@ -608,6 +635,9 @@ gdb_test_multiple "print (a.*pmf)(3)" $name { + } + } + ++gdb_test "ptype a.*pmf" "type = int \\(A \\*, int\\)" ++gdb_test "ptype (a.*pmf)(3)" "type = int" ++ + # Print out a pointer to data member which requires looking into + # a base class. + gdb_test "print diamond_pmi" "$vhn = &Base::x" +diff --git a/gdb/testsuite/gdb.cp/namespace-multiple-imports.cc b/gdb/testsuite/gdb.cp/namespace-multiple-imports.cc +new file mode 100644 +index 0000000..6b180d6 +--- /dev/null ++++ b/gdb/testsuite/gdb.cp/namespace-multiple-imports.cc +@@ -0,0 +1,20 @@ ++namespace A { ++ int x = 11; ++ namespace{ ++ int xx = 22; ++ } ++} ++ ++using namespace A; ++ ++namespace{ ++ int xxx = 33; ++}; ++ ++int main() ++{ ++ x; ++ xx; ++ xxx; ++ return 0; ++} +diff --git a/gdb/testsuite/gdb.cp/namespace-multiple-imports.exp b/gdb/testsuite/gdb.cp/namespace-multiple-imports.exp +new file mode 100644 +index 0000000..e4bb9f8 +--- /dev/null ++++ b/gdb/testsuite/gdb.cp/namespace-multiple-imports.exp +@@ -0,0 +1,49 @@ ++# Copyright 2008 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++if $tracelevel then { ++ strace $tracelevel ++} ++ ++set prms_id 0 ++set bug_id 0 ++ ++set testfile namespace-multiple-imports ++set srcfile ${testfile}.cc ++set binfile ${objdir}/${subdir}/${testfile} ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug c++}] != "" } { ++ untested "Couldn't compile test program" ++ return -1 ++} ++ ++# Get things started. ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++############################################ ++# test printing of namespace imported within ++# the function. ++ ++if ![runto_main] then { ++ perror "couldn't run to breakpoint main" ++ continue ++} ++ ++gdb_test "print x" "\\$\[0-9\].* = 11" ++gdb_test "print xx" "\\$\[0-9\].* = 22" ++gdb_test "print xxx" "\\$\[0-9\].* = 33" +diff --git a/gdb/testsuite/gdb.cp/namespace-using.cc b/gdb/testsuite/gdb.cp/namespace-using.cc +new file mode 100644 +index 0000000..97af850 +--- /dev/null ++++ b/gdb/testsuite/gdb.cp/namespace-using.cc +@@ -0,0 +1,131 @@ ++//-------------------------- ++namespace M{ ++ int x = 911; ++} ++ ++namespace N{ ++ int x = 912; ++} ++ ++int marker10(){ ++ using namespace M; ++ int y = x+1; // marker10 stop ++ using namespace N; ++ return y; ++} ++//-------------------------- ++namespace J { ++ int jx = 44; ++} ++ ++namespace K{ ++ int marker9(){ ++ //x; ++ return marker10(); ++ } ++} ++ ++namespace L{ ++ using namespace J; ++ int marker8(){ ++ jx; ++ return K::marker9(); ++ } ++} ++//-------------------------- ++ ++//-------------------------- ++namespace G{ ++ namespace H { ++ int ghx = 6; ++ } ++} ++ ++namespace I{ ++ ++ int marker7(){ ++ using namespace G::H; ++ ghx; ++ return L::marker8(); ++ } ++} ++//-------------------------- ++ ++//-------------------------- ++namespace E{ ++ namespace F{ ++ int efx = 5; ++ } ++} ++using namespace E::F; ++int marker6(){ ++ efx; ++ return I::marker7(); ++} ++//-------------------------- ++ ++namespace A ++{ ++ int _a = 1; ++ int x = 2; ++ ++} ++ ++namespace C ++{ ++ int cc = 3; ++} ++ ++namespace D ++{ ++ int dx = 4; ++} ++ ++using namespace C; ++int marker5() ++{ ++ cc; ++ return marker6(); ++} ++ ++int marker4() ++{ ++ using D::dx; ++ return marker5(); ++} ++ ++int marker3() ++{ ++ return marker4(); ++} ++ ++int marker2() ++{ ++ namespace B = A; ++ B::_a; ++ return marker3(); ++} ++ ++int marker1() ++{ ++ int total = 0; ++ { ++ int b = 1; ++ { ++ using namespace A; ++ int c = 2; ++ { ++ int d = 3; ++ total = _a + b + c + d + marker2(); // marker1 stop ++ } ++ } ++ } ++ return total; ++} ++ ++int main() ++{ ++ using namespace A; ++ _a; ++ return marker1(); ++} +diff --git a/gdb/testsuite/gdb.cp/namespace-using.exp b/gdb/testsuite/gdb.cp/namespace-using.exp +new file mode 100644 +index 0000000..f73fa67 +--- /dev/null ++++ b/gdb/testsuite/gdb.cp/namespace-using.exp +@@ -0,0 +1,186 @@ ++# Copyright 2008 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++if $tracelevel then { ++ strace $tracelevel ++} ++ ++set prms_id 0 ++set bug_id 0 ++ ++set testfile namespace-using ++set srcfile ${testfile}.cc ++set binfile ${objdir}/${subdir}/${testfile} ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug c++}] != "" } { ++ untested "Couldn't compile test program" ++ return -1 ++} ++ ++# Get things started. ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++############################################ ++# test printing of namespace imported within ++# the function. ++ ++if ![runto_main] then { ++ perror "couldn't run to breakpoint main" ++ continue ++} ++ ++gdb_test "print _a" "= 1" ++ ++# Test that names are not printed when they ++# are not imported ++ ++gdb_breakpoint marker3 ++gdb_continue_to_breakpoint "marker3" ++ ++#send_gdb "break marker3\n" ++#send_gdb "continue\n" ++ ++gdb_test "print _a" "No symbol \"_a\" in current context." "Print _a without import" ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++ ++############################################ ++# test printing of namespace imported into ++# a scope containing the pc. ++ ++if ![runto_main] then { ++ perror "couldn't run to breakpoint main" ++ continue ++} ++ ++gdb_breakpoint [gdb_get_line_number "marker1 stop"] ++gdb_continue_to_breakpoint "marker1 stop" ++ ++gdb_test "print _a" "= 1" "print _a in a nested scope" ++ ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++############################################ ++# test printing of namespace imported into ++# file scope. ++ ++ ++if ![runto marker5] then { ++ perror "couldn't run to breakpoint marker5" ++ continue ++} ++ ++gdb_test "print cc" "= 3" ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++ ++############################################ ++# Test printing of namespace aliases ++ ++if ![runto marker2] then { ++ perror "couldn't run to breakpoint marker2" ++ continue ++} ++ ++gdb_test "print B::_a" "= 1" ++ ++gdb_test "print _a" "No symbol \"_a\" in current context." "print _a in namespace alias scope" ++gdb_test "print x" "No symbol \"x\" in current context." "print x in namespace alias scope" ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++ ++############################################ ++# Test printing of namespace aliases ++ ++if ![runto marker4] then { ++ perror "couldn't run to breakpoint marker4" ++ continue ++} ++ ++gdb_test "print dx" "= 4" ++ ++############################################ ++# Test printing of namespace aliases ++ ++if ![runto marker6] then { ++ perror "couldn't run to breakpoint marker6" ++ continue ++} ++ ++gdb_test "print efx" "= 5" ++ ++############################################ ++# Test printing of variables imported from ++# nested namespaces ++ ++if ![runto I::marker7] then { ++ perror "couldn't run to breakpoint I::marker7" ++ continue ++} ++ ++gdb_test "print ghx" "= 6" ++ ++############################################ ++# Test that variables are not printed in a namespace ++# that is sibling to the namespace containing an import ++ ++if ![runto L::marker8] then { ++ perror "couldn't run to breakpoint L::marker8" ++ continue ++} ++ ++gdb_test "print jx" "= 44" ++ ++gdb_breakpoint "K::marker9" ++gdb_continue_to_breakpoint "K::marker9" ++ ++gdb_test "print jx" "No symbol \"jx\" in current context." ++ ++############################################ ++# Test that variables are only printed after the line ++# containing the import ++ ++if ![runto_main] then { ++ perror "couldn't run to breakpoint main" ++ continue ++} ++ ++gdb_breakpoint [gdb_get_line_number "marker10 stop"] ++gdb_continue_to_breakpoint "marker10 stop" ++ ++gdb_test "print x" "= 911" "print x (from M::x)" ++ ++gdb_test "next" "" ++ ++gdb_test "print x" "= 912" "print x (from M::x)" +diff --git a/gdb/testsuite/gdb.cp/namespace.exp b/gdb/testsuite/gdb.cp/namespace.exp +index 76b1b82..2042db2 100644 +--- a/gdb/testsuite/gdb.cp/namespace.exp ++++ b/gdb/testsuite/gdb.cp/namespace.exp +@@ -24,6 +24,7 @@ + # for namespaces. + # Note: As of 2000-06-03, they passed under g++ - djb + ++load_lib "cp-support.exp" + + if $tracelevel then { + strace $tracelevel +@@ -259,11 +260,16 @@ gdb_test "ptype E" "type = namespace C::D::E" + gdb_test "ptype CClass" "type = (class C::CClass \{\r\n public:|struct C::CClass \{)\r\n int x;\r\n\}" + gdb_test "ptype CClass::NestedClass" "type = (class C::CClass::NestedClass \{\r\n public:|struct C::CClass::NestedClass \{)\r\n int y;\r\n\}" + gdb_test "ptype NestedClass" "No symbol \"NestedClass\" in current context." +-setup_kfail "gdb/1448" "*-*-*" +-gdb_test "ptype ::C::CClass" "type = class C::CClass \{\r\n public:\r\n int x;\r\n\}" +-setup_kfail "gdb/1448" "*-*-*" +-gdb_test "ptype ::C::CClass::NestedClass" "type = class C::CClass::NestedClass \{\r\n public:\r\n int y;\r\n\}" +-setup_kfail "gdb/1448" "*-*-*" ++cp_test_ptype_class \ ++ "ptype ::C::CClass" "" "class" "C::CClass" \ ++ { ++ { field public "int x;" } ++ } ++cp_test_ptype_class \ ++ "ptype ::C::CClass::NestedClass" "" "class" "C::CClass::NestedClass" \ ++ { ++ { field public "int y;" } ++ } + gdb_test "ptype ::C::NestedClass" "No symbol \"NestedClass\" in namespace \"C\"." + gdb_test "ptype C::CClass" "No symbol \"CClass\" in namespace \"C::C\"." + gdb_test "ptype C::CClass::NestedClass" "No type \"CClass\" within class or namespace \"C::C\"." +@@ -273,8 +279,11 @@ gdb_test "ptype C::NestedClass" "No symbol \"NestedClass\" in namespace \"C::C\" + + gdb_test "print cOtherFile" "\\$\[0-9\].* = 316" + gdb_test "ptype OtherFileClass" "type = (class C::OtherFileClass \{\r\n public:|struct C::OtherFileClass \{)\r\n int z;\r\n\}" +-setup_kfail "gdb/1448" "*-*-*" +-gdb_test "ptype ::C::OtherFileClass" "type = class C::OtherFileClass \{\r\n public:\r\n int z;\r\n\}" ++cp_test_ptype_class \ ++ "ptype ::C::OtherFileClass" "" "class" "C::OtherFileClass" \ ++ { ++ { field public "int z;" } ++ } + gdb_test "ptype C::OtherFileClass" "No symbol \"OtherFileClass\" in namespace \"C::C\"." + + # Some anonymous namespace tests. +diff --git a/gdb/testsuite/gdb.cp/overload.exp b/gdb/testsuite/gdb.cp/overload.exp +index 24025a2..a72932e 100644 +--- a/gdb/testsuite/gdb.cp/overload.exp ++++ b/gdb/testsuite/gdb.cp/overload.exp +@@ -74,12 +74,12 @@ set re_methods "${re_methods}${ws}int overload1arg\\((void|)\\);" + set re_methods "${re_methods}${ws}int overload1arg\\(char\\);" + set re_methods "${re_methods}${ws}int overload1arg\\(signed char\\);" + set re_methods "${re_methods}${ws}int overload1arg\\(unsigned char\\);" +-set re_methods "${re_methods}${ws}int overload1arg\\(short\\);" +-set re_methods "${re_methods}${ws}int overload1arg\\(unsigned short\\);" ++set re_methods "${re_methods}${ws}int overload1arg\\(short( int)?\\);" ++set re_methods "${re_methods}${ws}int overload1arg\\((unsigned short|short unsigned)( int)?\\);" + set re_methods "${re_methods}${ws}int overload1arg\\(int\\);" + set re_methods "${re_methods}${ws}int overload1arg\\(unsigned int\\);" +-set re_methods "${re_methods}${ws}int overload1arg\\(long\\);" +-set re_methods "${re_methods}${ws}int overload1arg\\(unsigned long\\);" ++set re_methods "${re_methods}${ws}int overload1arg\\(long( int)?\\);" ++set re_methods "${re_methods}${ws}int overload1arg\\((unsigned long|long unsigned)( int)?\\);" + set re_methods "${re_methods}${ws}int overload1arg\\(float\\);" + set re_methods "${re_methods}${ws}int overload1arg\\(double\\);" + set re_methods "${re_methods}${ws}int overloadfnarg\\((void|)\\);" +diff --git a/gdb/testsuite/gdb.cp/ovldbreak.exp b/gdb/testsuite/gdb.cp/ovldbreak.exp +index 8a6b795..897171c 100644 +--- a/gdb/testsuite/gdb.cp/ovldbreak.exp ++++ b/gdb/testsuite/gdb.cp/ovldbreak.exp +@@ -127,10 +127,24 @@ proc set_bp_overloaded {name expectedmenu mychoice bpnumber linenumber} { + } + + # This is the expected menu for overload1arg. +-# Note the arg type variations on lines 6 and 13. ++# Note the arg type variations for void and integer types. + # This accommodates different versions of g++. + +-set menu_overload1arg "\\\[0\\\] cancel\r\n\\\[1\\\] all\r\n\\\[2\\\] foo::overload1arg\\(double\\) at.*$srcfile:121\r\n\\\[3\\\] foo::overload1arg\\(float\\) at.*$srcfile:120\r\n\\\[4\\\] foo::overload1arg\\(unsigned long\\) at.*$srcfile:119\r\n\\\[5\\\] foo::overload1arg\\(long\\) at.*$srcfile:118\r\n\\\[6\\\] foo::overload1arg\\((unsigned int|unsigned)\\) at.*$srcfile:117\r\n\\\[7\\\] foo::overload1arg\\(int\\) at.*$srcfile:116\r\n\\\[8\\\] foo::overload1arg\\(unsigned short\\) at.*$srcfile:115\r\n\\\[9\\\] foo::overload1arg\\(short\\) at.*$srcfile:114\r\n\\\[10\\\] foo::overload1arg\\(unsigned char\\) at.*$srcfile:113\r\n\\\[11\\\] foo::overload1arg\\(signed char\\) at.*$srcfile:112\r\n\\\[12\\\] foo::overload1arg\\(char\\) at.*$srcfile:111\r\n\\\[13\\\] foo::overload1arg\\((void|)\\) at.*$srcfile:110\r\n> $" ++set menu_overload1arg "\\\[0\\\] cancel\r\n" ++append menu_overload1arg "\\\[1\\\] all\r\n" ++append menu_overload1arg "\\\[2\\\] foo::overload1arg\\(double\\) at.*$srcfile:121\r\n" ++append menu_overload1arg "\\\[3\\\] foo::overload1arg\\(float\\) at.*$srcfile:120\r\n" ++append menu_overload1arg "\\\[4\\\] foo::overload1arg\\((unsigned long|long unsigned)( int)?\\) at.*$srcfile:119\r\n" ++append menu_overload1arg "\\\[5\\\] foo::overload1arg\\(long( int)?\\) at.*$srcfile:118\r\n" ++append menu_overload1arg "\\\[6\\\] foo::overload1arg\\((unsigned int|unsigned)\\) at.*$srcfile:117\r\n" ++append menu_overload1arg "\\\[7\\\] foo::overload1arg\\(int\\) at.*$srcfile:116\r\n" ++append menu_overload1arg "\\\[8\\\] foo::overload1arg\\((unsigned short|short unsigned)( int)?\\) at.*$srcfile:115\r\n" ++append menu_overload1arg "\\\[9\\\] foo::overload1arg\\(short( int)?\\) at.*$srcfile:114\r\n" ++append menu_overload1arg "\\\[10\\\] foo::overload1arg\\(unsigned char\\) at.*$srcfile:113\r\n" ++append menu_overload1arg "\\\[11\\\] foo::overload1arg\\(signed char\\) at.*$srcfile:112\r\n" ++append menu_overload1arg "\\\[12\\\] foo::overload1arg\\(char\\) at.*$srcfile:111\r\n" ++append menu_overload1arg "\\\[13\\\] foo::overload1arg\\((void|)\\) at.*$srcfile:110\r\n" ++append menu_overload1arg "> $" + + # Set multiple-symbols to "ask", to allow us to test the use + # of the multiple-choice menu when breaking on an overloaded method. +@@ -157,17 +171,17 @@ set_bp_overloaded "foo::overload1arg" "$menu_overload1arg" 13 13 110 + + gdb_test "info break" \ + "Num Type\[\t \]+Disp Enb Address\[\t \]+What.* +-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in main at.*$srcfile:49\r ++\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in main(\\(void\\))? at.*$srcfile:49\r + \[\t \]+breakpoint already hit 1 time\r + \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(char\\) at.*$srcfile:111\r + \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(signed char\\) at.*$srcfile:112\r + \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(unsigned char\\) at.*$srcfile:113\r +-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(short\\) at.*$srcfile:114\r +-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(unsigned short\\) at.*$srcfile:115\r ++\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(short( int)?\\) at.*$srcfile:114\r ++\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned short|short unsigned)( int)?\\) at.*$srcfile:115\r + \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(int\\) at.*$srcfile:116\r + \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned|unsigned int)\\) at.*$srcfile:117\r +-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(long\\) at.*$srcfile:118\r +-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(unsigned long\\) at.*$srcfile:119\r ++\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(long( int)?\\) at.*$srcfile:118\r ++\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned long|long unsigned)( int)?\\) at.*$srcfile:119\r + \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(float\\) at.*$srcfile:120\r + \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(double\\) at.*$srcfile:121\r + \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((void|)\\) at.*$srcfile:110" \ +@@ -215,17 +229,17 @@ gdb_expect { + + gdb_test "info break" \ + "Num Type\[\t \]+Disp Enb Address\[\t \]+What.* +-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in main at.*$srcfile:49\r ++\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in main(\\(void\\))? at.*$srcfile:49\r + \[\t \]+breakpoint already hit 1 time\r + \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(char\\) at.*$srcfile:111\r + \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(signed char\\) at.*$srcfile:112\r + \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(unsigned char\\) at.*$srcfile:113\r +-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(short\\) at.*$srcfile:114\r +-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(unsigned short\\) at.*$srcfile:115\r ++\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(short( int)?\\) at.*$srcfile:114\r ++\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned short|short unsigned)( int)?\\) at.*$srcfile:115\r + \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(int\\) at.*$srcfile:116\r + \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned|unsigned int)\\) at.*$srcfile:117\r +-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(long\\) at.*$srcfile:118\r +-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(unsigned long\\) at.*$srcfile:119\r ++\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(long( int)?\\) at.*$srcfile:118\r ++\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned long|long unsigned)( int)?\\) at.*$srcfile:119\r + \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(float\\) at.*$srcfile:120\r + \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(double\\) at.*$srcfile:121\r + \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((void|)\\) at.*$srcfile:110" \ +@@ -296,12 +310,12 @@ gdb_test "info break" \ + "Num Type\[\t \]+Disp Enb Address\[\t \]+What.* + \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(double\\) at.*$srcfile:121\r + \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(float\\) at.*$srcfile:120\r +-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(unsigned long\\) at.*$srcfile:119\r +-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(long\\) at.*$srcfile:118\r ++\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned long|long unsigned)( int)?\\) at.*$srcfile:119\r ++\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(long( int)?\\) at.*$srcfile:118\r + \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned|unsigned int)\\) at.*$srcfile:117\r + \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(int\\) at.*$srcfile:116\r +-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(unsigned short\\) at.*$srcfile:115\r +-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(short\\) at.*$srcfile:114\r ++\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned short|short unsigned)( int)?\\) at.*$srcfile:115\r ++\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(short( int)?\\) at.*$srcfile:114\r + \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(unsigned char\\) at.*$srcfile:113\r + \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(signed char\\) at.*$srcfile:112\r + \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(char\\) at.*$srcfile:111\r +diff --git a/gdb/testsuite/gdb.cp/ref-types.exp b/gdb/testsuite/gdb.cp/ref-types.exp +index 4784cb2..b2e55cf 100644 +--- a/gdb/testsuite/gdb.cp/ref-types.exp ++++ b/gdb/testsuite/gdb.cp/ref-types.exp +@@ -284,7 +284,7 @@ gdb_expect { + + send_gdb "print UC\n" + gdb_expect { +- -re ".\[0-9\]* = 21 '\.025'\.*$gdb_prompt $" { ++ -re ".\[0-9\]* = 21 '\.25'\.*$gdb_prompt $" { + pass "print value of UC" + } + -re ".*$gdb_prompt $" { fail "print value of UC" } +@@ -557,7 +557,7 @@ gdb_expect { + + send_gdb "print rUC\n" + gdb_expect { +- -re ".\[0-9\]* = \\(unsigned char &\\) @$hex: 21 \'.025\'.*$gdb_prompt $" { ++ -re ".\[0-9\]* = \\(unsigned char &\\) @$hex: 21 \'.25\'.*$gdb_prompt $" { + pass "print value of rUC" + } + -re ".*$gdb_prompt $" { fail "print value of rUC" } +diff --git a/gdb/testsuite/gdb.cp/templates.exp b/gdb/testsuite/gdb.cp/templates.exp +index cd9b770..f49caff 100644 +--- a/gdb/testsuite/gdb.cp/templates.exp ++++ b/gdb/testsuite/gdb.cp/templates.exp +@@ -329,13 +329,11 @@ gdb_expect { + + send_gdb "print Foo::foo\n" + gdb_expect { +- -re "\\$\[0-9\]* = \\{.*char \\*\\((class |)Foo \\*(| const), int, .*char \\*\\)\\} $hex ::foo\\(int, .*char.*\\*\\)>\r\n$gdb_prompt $" { pass "print Foo::foo" } ++ -re "\\$\[0-9\]* = \\{.*char \\*\\((class |)Foo<(volatile char|char volatile) ?\\*> \\*(| const), int, .*char \\*\\)\\} $hex ::foo\\(int, .*char.*\\*\\)>\r\n$gdb_prompt $" { pass "print Foo::foo" } + -re "No symbol \"Foo\" in current context.\r\n$gdb_prompt $" + { +- # This used to be a kfail gdb/33. That problem has been +- # fixed, but now gdb/931 and gdb/1512 are rearing their ugly +- # heads. +- kfail "gdb/931" "print Foo::foo" ++ # This used to be a kfail gdb/33 and then kfail gdb/931. ++ fail "print Foo::foo" + } + -re "$gdb_prompt $" { fail "print Foo::foo" } + timeout { fail "(timeout) print Foo::foo" } +@@ -343,13 +341,11 @@ gdb_expect { + + send_gdb "print Foo::foo\n" + gdb_expect { +- -re "\\$\[0-9\]* = \\{.*char \\*\\((class |)Foo \\*(| const), int, .*char \\*\\)\\} $hex ::foo\\(int, .*char.*\\*\\)>\r\n$gdb_prompt $" { pass "print Foo::foo" } ++ -re "\\$\[0-9\]* = \\{.*char \\*\\((class |)Foo<(volatile char|char volatile) ?\\*> \\*(| const), int, .*char \\*\\)\\} $hex ::foo\\(int, .*char.*\\*\\)>\r\n$gdb_prompt $" { pass "print Foo::foo" } + -re "No symbol \"Foo\" in current context.\r\n$gdb_prompt $" + { +- # This used to be a kfail gdb/33. That problem has been +- # fixed, but now gdb/931 and gdb/1512 are rearing their ugly +- # heads. +- kfail "gdb/931" "print Foo::foo" ++ # This used to be a kfail gdb/33 and then kfail gdb/931. ++ fail "print Foo::foo" + } + -re "$gdb_prompt $" { fail "print Foo::foo" } + timeout { fail "(timeout) print Foo::foo" } +@@ -459,7 +455,7 @@ send_gdb "ptype quxint\n" + gdb_expect { + -re "type = class Qux \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*int t;\r\n\r\n\[ \t\]*.*int qux\\(int, int\\);\r\n\\}\r\n$gdb_prompt $" { pass "ptype quxint" } + -re "type = class Qux \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*int t;\r\n\r\n\[ \t\]*int qux\\(int, int\\);.*\r\n\\}\r\n$gdb_prompt $" { pass "ptype quxint" } +- -re "type = class Qux \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*int t;\r\n\r\n\[ \t\]*int qux\\(int, int\\);.*\r\n\\}\r\n$gdb_prompt $" { pass "ptype quxint" } ++ -re "type = class Qux \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*int t;\r\n\r\n\[ \t\]*int qux\\(int, int\\);.*\r\n\\}\r\n$gdb_prompt $" { pass "ptype quxint" } + -re "type = class Qux \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*int t;\r\n\r\n\[ \t\]*int qux\\(int, int\\);.*\r\n\\}\r\n$gdb_prompt $" { + kfail "gdb/1512" "ptype quxint" + } +diff --git a/gdb/testsuite/gdb.dwarf2/dw2-stripped.c b/gdb/testsuite/gdb.dwarf2/dw2-stripped.c +new file mode 100644 +index 0000000..1f02d90 +--- /dev/null ++++ b/gdb/testsuite/gdb.dwarf2/dw2-stripped.c +@@ -0,0 +1,42 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2004 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ USA. */ ++ ++ ++/* The function `func1' traced into must have debug info on offset > 0; ++ (DW_UNSND (attr)). This is the reason of `func0' existence. */ ++ ++void ++func0(int a, int b) ++{ ++} ++ ++/* `func1' being traced into must have some arguments to dump. */ ++ ++void ++func1(int a, int b) ++{ ++ func0 (a,b); ++} ++ ++int ++main(void) ++{ ++ func1 (1, 2); ++ return 0; ++} +diff --git a/gdb/testsuite/gdb.dwarf2/dw2-stripped.exp b/gdb/testsuite/gdb.dwarf2/dw2-stripped.exp +new file mode 100644 +index 0000000..1c6e84a +--- /dev/null ++++ b/gdb/testsuite/gdb.dwarf2/dw2-stripped.exp +@@ -0,0 +1,79 @@ ++# Copyright 2006 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++# Minimal DWARF-2 unit test ++ ++# This test can only be run on targets which support DWARF-2. ++# For now pick a sampling of likely targets. ++if {![istarget *-*-linux*] ++ && ![istarget *-*-gnu*] ++ && ![istarget *-*-elf*] ++ && ![istarget *-*-openbsd*] ++ && ![istarget arm-*-eabi*] ++ && ![istarget powerpc-*-eabi*]} { ++ return 0 ++} ++ ++set testfile "dw2-stripped" ++set srcfile ${testfile}.c ++set binfile ${objdir}/${subdir}/${testfile}.x ++ ++remote_exec build "rm -f ${binfile}" ++ ++# get the value of gcc_compiled ++if [get_compiler_info ${binfile}] { ++ return -1 ++} ++ ++# This test can only be run on gcc as we use additional_flags=FIXME ++if {$gcc_compiled == 0} { ++ return 0 ++} ++ ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug additional_flags=-ggdb3}] != "" } { ++ return -1 ++} ++ ++remote_exec build "objcopy -R .debug_loc ${binfile}" ++set strip_output [remote_exec build "objdump -h ${binfile}"] ++ ++set test "stripping test file preservation" ++if [ regexp ".debug_info " $strip_output] { ++ pass "$test (.debug_info preserved)" ++} else { ++ fail "$test (.debug_info got also stripped)" ++} ++ ++set test "stripping test file functionality" ++if [ regexp ".debug_loc " $strip_output] { ++ fail "$test (.debug_loc still present)" ++} else { ++ pass "$test (.debug_loc stripped)" ++} ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++# For C programs, "start" should stop in main(). ++ ++gdb_test "start" \ ++ ".*main \\(\\) at .*" \ ++ "start" ++gdb_test "step" \ ++ "func.* \\(.*\\) at .*" \ ++ "step" +diff --git a/gdb/testsuite/gdb.fortran/common-block.exp b/gdb/testsuite/gdb.fortran/common-block.exp +new file mode 100644 +index 0000000..888f6c3 +--- /dev/null ++++ b/gdb/testsuite/gdb.fortran/common-block.exp +@@ -0,0 +1,101 @@ ++# Copyright 2008 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++# This file was written by Jan Kratochvil . ++ ++set testfile "common-block" ++set srcfile ${testfile}.f90 ++set binfile ${objdir}/${subdir}/${testfile} ++ ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug f77 quiet}] != "" } { ++ untested "Couldn't compile ${srcfile}" ++ return -1 ++} ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++if ![runto MAIN__] then { ++ perror "couldn't run to breakpoint MAIN__" ++ continue ++} ++ ++gdb_breakpoint [gdb_get_line_number "stop-here-out"] ++gdb_continue_to_breakpoint "stop-here-out" ++ ++# Common block naming with source name /foo/: ++# .symtab DW_TAG_common_block's DW_AT_name ++# Intel Fortran foo_ foo_ ++# GNU Fortran foo_ foo ++#set suffix "_" ++set suffix "" ++ ++set int4 {(integer\(kind=4\)|INTEGER\(4\))} ++set real4 {(real\(kind=4\)|REAL\(4\))} ++set real8 {(real\(kind=8\)|REAL\(8\))} ++ ++gdb_test "whatis foo$suffix" "No symbol \"foo$suffix\" in current context." ++gdb_test "ptype foo$suffix" "No symbol \"foo$suffix\" in current context." ++gdb_test "p foo$suffix" "No symbol \"foo$suffix\" in current context." ++gdb_test "whatis fo_o$suffix" "No symbol \"fo_o$suffix\" in current context." ++gdb_test "ptype fo_o$suffix" "No symbol \"fo_o$suffix\" in current context." ++gdb_test "p fo_o$suffix" "No symbol \"fo_o$suffix\" in current context." ++ ++gdb_test "info locals" "ix_x = 11\r\niy_y = 22\r\niz_z = 33\r\nix = 1\r\niy = 2\r\niz = 3" "info locals out" ++gdb_test "info common" "Contents of F77 COMMON block 'fo_o':\r\nix_x = 11\r\niy_y = 22\r\niz_z = 33\r\n\r\nContents of F77 COMMON block 'foo':\r\nix = 1\r\niy = 2\r\niz = 3" "info common out" ++ ++gdb_test "ptype ix" "type = $int4" "ptype ix out" ++gdb_test "ptype iy" "type = $real4" "ptype iy out" ++gdb_test "ptype iz" "type = $real8" "ptype iz out" ++gdb_test "ptype ix_x" "type = $int4" "ptype ix_x out" ++gdb_test "ptype iy_y" "type = $real4" "ptype iy_y out" ++gdb_test "ptype iz_z" "type = $real8" "ptype iz_z out" ++ ++gdb_test "p ix" " = 1 *" "p ix out" ++gdb_test "p iy" " = 2 *" "p iy out" ++gdb_test "p iz" " = 3 *" "p iz out" ++gdb_test "p ix_x" " = 11 *" "p ix_x out" ++gdb_test "p iy_y" " = 22 *" "p iy_y out" ++gdb_test "p iz_z" " = 33 *" "p iz_z out" ++ ++gdb_breakpoint [gdb_get_line_number "stop-here-in"] ++gdb_continue_to_breakpoint "stop-here-in" ++ ++gdb_test "whatis foo$suffix" "No symbol \"foo$suffix\" in current context." "whatis foo$suffix in" ++gdb_test "ptype foo$suffix" "No symbol \"foo$suffix\" in current context." "ptype foo$suffix in" ++gdb_test "p foo$suffix" "No symbol \"foo$suffix\" in current context." "p foo$suffix in" ++gdb_test "whatis fo_o$suffix" "No symbol \"fo_o$suffix\" in current context." "whatis fo_o$suffix in" ++gdb_test "ptype fo_o$suffix" "No symbol \"fo_o$suffix\" in current context." "ptype fo_o$suffix in" ++gdb_test "p fo_o$suffix" "No symbol \"fo_o$suffix\" in current context." "p fo_o$suffix in" ++ ++gdb_test "info locals" "ix = 11\r\niy2 = 22\r\niz = 33\r\nix_x = 1\r\niy_y = 2\r\niz_z2 = 3\r\niy = 5\r\niz_z = 55" "info locals in" ++gdb_test "info common" "Contents of F77 COMMON block 'fo_o':\r\nix = 11\r\niy2 = 22\r\niz = 33\r\n\r\nContents of F77 COMMON block 'foo':\r\nix_x = 1\r\niy_y = 2\r\niz_z2 = 3" "info common in" ++ ++gdb_test "ptype ix" "type = $int4" "ptype ix in" ++gdb_test "ptype iy2" "type = $real4" "ptype iy2 in" ++gdb_test "ptype iz" "type = $real8" "ptype iz in" ++gdb_test "ptype ix_x" "type = $int4" "ptype ix_x in" ++gdb_test "ptype iy_y" "type = $real4" "ptype iy_y in" ++gdb_test "ptype iz_z2" "type = $real8" "ptype iz_z2 in" ++ ++gdb_test "p ix" " = 11 *" "p ix in" ++gdb_test "p iy2" " = 22 *" "p iy2 in" ++gdb_test "p iz" " = 33 *" "p iz in" ++gdb_test "p ix_x" " = 1 *" "p ix_x in" ++gdb_test "p iy_y" " = 2 *" "p iy_y in" ++gdb_test "p iz_z2" " = 3 *" "p iz_z2 in" +diff --git a/gdb/testsuite/gdb.fortran/common-block.f90 b/gdb/testsuite/gdb.fortran/common-block.f90 +new file mode 100644 +index 0000000..b614e8a +--- /dev/null ++++ b/gdb/testsuite/gdb.fortran/common-block.f90 +@@ -0,0 +1,67 @@ ++! Copyright 2008 Free Software Foundation, Inc. ++! ++! This program is free software; you can redistribute it and/or modify ++! it under the terms of the GNU General Public License as published by ++! the Free Software Foundation; either version 2 of the License, or ++! (at your option) any later version. ++! ++! This program is distributed in the hope that it will be useful, ++! but WITHOUT ANY WARRANTY; without even the implied warranty of ++! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++! GNU General Public License for more details. ++! ++! You should have received a copy of the GNU General Public License ++! along with this program; if not, write to the Free Software ++! Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++! ++! Ihis file is the Fortran source file for dynamic.exp. ++! Original file written by Jakub Jelinek . ++! Modified for the GDB testcase by Jan Kratochvil . ++ ++subroutine in ++ ++ INTEGER*4 ix ++ REAL*4 iy2 ++ REAL*8 iz ++ ++ INTEGER*4 ix_x ++ REAL*4 iy_y ++ REAL*8 iz_z2 ++ ++ common /fo_o/ix,iy2,iz ++ common /foo/ix_x,iy_y,iz_z2 ++ ++ iy = 5 ++ iz_z = 55 ++ ++ if (ix .ne. 11 .or. iy2 .ne. 22.0 .or. iz .ne. 33.0) call abort ++ if (ix_x .ne. 1 .or. iy_y .ne. 2.0 .or. iz_z2 .ne. 3.0) call abort ++ ++ ix = 0 ! stop-here-in ++ ++end subroutine in ++ ++program common_test ++ ++ INTEGER*4 ix ++ REAL*4 iy ++ REAL*8 iz ++ ++ INTEGER*4 ix_x ++ REAL*4 iy_y ++ REAL*8 iz_z ++ ++ common /foo/ix,iy,iz ++ common /fo_o/ix_x,iy_y,iz_z ++ ++ ix = 1 ++ iy = 2.0 ++ iz = 3.0 ++ ++ ix_x = 11 ++ iy_y = 22.0 ++ iz_z = 33.0 ++ ++ call in ! stop-here-out ++ ++end program common_test +diff --git a/gdb/testsuite/gdb.fortran/dynamic.exp b/gdb/testsuite/gdb.fortran/dynamic.exp +new file mode 100644 +index 0000000..77a1203 +--- /dev/null ++++ b/gdb/testsuite/gdb.fortran/dynamic.exp +@@ -0,0 +1,156 @@ ++# Copyright 2007 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++# This file was written by Jan Kratochvil . ++ ++# This file is part of the gdb testsuite. It contains tests for dynamically ++# allocated Fortran arrays. ++# It depends on the GCC dynamic Fortran arrays DWARF support: ++# http://gcc.gnu.org/bugzilla/show_bug.cgi?id=22244 ++ ++set testfile "dynamic" ++set srcfile ${testfile}.f90 ++set binfile ${objdir}/${subdir}/${testfile} ++ ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug f77 quiet}] != "" } { ++ untested "Couldn't compile ${srcfile}" ++ return -1 ++} ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++if ![runto MAIN__] then { ++ perror "couldn't run to breakpoint MAIN__" ++ continue ++} ++ ++gdb_breakpoint [gdb_get_line_number "varx-init"] ++gdb_continue_to_breakpoint "varx-init" ++gdb_test "p varx" "\\$\[0-9\]* = <(object|the array) is not allocated>" "p varx unallocated" ++gdb_test "ptype varx" "type = <(object|the array) is not allocated>" "ptype varx unallocated" ++gdb_test "p varx(1,5,17)" "(Cannot access it|Unable to access the object) because the (object|array) is not allocated\\." "p varx(1,5,17) unallocated" ++gdb_test "p varx(1,5,17)=1" "(Cannot access it|Unable to access the object) because the (object|array) is not allocated\\." "p varx(1,5,17)=1 unallocated" ++gdb_test "ptype varx(1,5,17)" "(Cannot access it|Unable to access the object) because the (object|array) is not allocated\\." "ptype varx(1,5,17) unallocated" ++ ++gdb_breakpoint [gdb_get_line_number "varx-allocated"] ++gdb_continue_to_breakpoint "varx-allocated" ++# $1 = (( ( 0, 0, 0, 0, 0, 0) ( 0, 0, 0, 0, 0, 0) --- , 0) ) ( ( 0, 0, ...) ...) ...) ++gdb_test "ptype varx" "type = real(\\(kind=4\\)|\\*4) \\(6,5:15,17:28\\)" "ptype varx allocated" ++# Intel Fortran Compiler 10.1.008 uses -1 there, GCC uses 1. ++gdb_test "p l" "\\$\[0-9\]* = (\\.TRUE\\.|4294967295)" "p l if varx allocated" ++ ++gdb_breakpoint [gdb_get_line_number "varx-filled"] ++gdb_continue_to_breakpoint "varx-filled" ++gdb_test "p varx(2, 5, 17)" "\\$\[0-9\]* = 6" ++gdb_test "p varx(1, 5, 17)" "\\$\[0-9\]* = 7" ++gdb_test "p varx(2, 6, 18)" "\\$\[0-9\]* = 8" ++gdb_test "p varx(6, 15, 28)" "\\$\[0-9\]* = 9" ++# The latter one is for the Intel Fortran Compiler 10.1.008 pointer type. ++gdb_test "p varv" "\\$\[0-9\]* = (<(object|the array) is not associated>|.*(Cannot access it|Unable to access the object) because the object is not associated.)" "p varv unassociated" ++gdb_test "ptype varv" "type = (<(object|the array) is not associated>|.*(Cannot access it|Unable to access the object) because the object is not associated.)" "ptype varv unassociated" ++ ++gdb_breakpoint [gdb_get_line_number "varv-associated"] ++gdb_continue_to_breakpoint "varv-associated" ++gdb_test "p varx(3, 7, 19)" "\\$\[0-9\]* = 6" "p varx(3, 7, 19) with varv associated" ++gdb_test "p varv(3, 7, 19)" "\\$\[0-9\]* = 6" "p varv(3, 7, 19) associated" ++# Intel Fortran Compiler 10.1.008 uses -1 there, GCC uses 1. ++gdb_test "p l" "\\$\[0-9\]* = (\\.TRUE\\.|4294967295)" "p l if varv associated" ++gdb_test "ptype varx" "type = real(\\(kind=4\\)|\\*4) \\(6,5:15,17:28\\)" "ptype varx with varv associated" ++# Intel Fortran Compiler 10.1.008 uses the pointer type. ++gdb_test "ptype varv" "type = (PTR TO -> \\( )?real(\\(kind=4\\)|\\*4) \\(6,5:15,17:28\\)\\)?" "ptype varv associated" ++ ++gdb_breakpoint [gdb_get_line_number "varv-filled"] ++gdb_continue_to_breakpoint "varv-filled" ++gdb_test "p varx(3, 7, 19)" "\\$\[0-9\]* = 10" "p varx(3, 7, 19) with varv filled" ++gdb_test "p varv(3, 7, 19)" "\\$\[0-9\]* = 10" "p varv(3, 7, 19) filled" ++ ++gdb_breakpoint [gdb_get_line_number "varv-deassociated"] ++gdb_continue_to_breakpoint "varv-deassociated" ++# The latter one is for the Intel Fortran Compiler 10.1.008 pointer type. ++gdb_test "p varv" "\\$\[0-9\]* = (<(object|the array) is not associated>|.*(Cannot access it|Unable to access the object) because the object is not associated.)" "p varv deassociated" ++gdb_test "ptype varv" "type = (<(object|the array) is not associated>|.*(Cannot access it|Unable to access the object) because the object is not associated.)" "ptype varv deassociated" ++gdb_test "p l" "\\$\[0-9\]* = \\.FALSE\\." "p l if varv deassociated" ++gdb_test "p varv(1,5,17)" "(Cannot access it|Unable to access the object) because the (object|array) is not associated\\." ++gdb_test "ptype varv(1,5,17)" "(Cannot access it|Unable to access the object) because the (object|array) is not associated\\." ++ ++gdb_breakpoint [gdb_get_line_number "varx-deallocated"] ++gdb_continue_to_breakpoint "varx-deallocated" ++gdb_test "p varx" "\\$\[0-9\]* = <(object|the array) is not allocated>" "p varx deallocated" ++gdb_test "ptype varx" "type = <(object|the array) is not allocated>" "ptype varx deallocated" ++gdb_test "p l" "\\$\[0-9\]* = \\.FALSE\\." "p l if varx deallocated" ++gdb_test "p varx(1,5,17)" "(Cannot access it|Unable to access the object) because the (object|array) is not allocated\\." "p varx(1,5,17) deallocated" ++gdb_test "ptype varx(1,5,17)" "(Cannot access it|Unable to access the object) because the (object|array) is not allocated\\." "ptype varx(1,5,17) deallocated" ++ ++gdb_breakpoint [gdb_get_line_number "vary-passed"] ++gdb_continue_to_breakpoint "vary-passed" ++# $1 = (( ( 1, 1, 1, 1, 1, 1) ( 1, 1, 1, 1, 1, 1) --- , 1) ) ( ( 1, 1, ...) ...) ...) ++gdb_test "p vary" "\\$\[0-9\]* = \\(\[()1, .\]*\\)" ++ ++gdb_breakpoint [gdb_get_line_number "vary-filled"] ++gdb_continue_to_breakpoint "vary-filled" ++gdb_test "ptype vary" "type = real(\\(kind=4\\)|\\*4) \\(10,10\\)" ++gdb_test "p vary(1, 1)" "\\$\[0-9\]* = 8" ++gdb_test "p vary(2, 2)" "\\$\[0-9\]* = 9" ++gdb_test "p vary(1, 3)" "\\$\[0-9\]* = 10" ++# $1 = (( ( 3, 3, 3, 3, 3, 3) ( 3, 3, 3, 3, 3, 3) --- , 3) ) ( ( 3, 3, ...) ...) ...) ++gdb_test "p varw" "\\$\[0-9\]* = \\(\[()3, .\]*\\)" ++ ++gdb_breakpoint [gdb_get_line_number "varw-almostfilled"] ++gdb_continue_to_breakpoint "varw-almostfilled" ++gdb_test "ptype varw" "type = real(\\(kind=4\\)|\\*4) \\(5,4,3\\)" ++gdb_test "p varw(3,1,1)=1" "\\$\[0-9\]* = 1" ++# $1 = (( ( 6, 5, 1, 5, 5, 5) ( 5, 5, 5, 5, 5, 5) --- , 5) ) ( ( 5, 5, ...) ...) ...) ++gdb_test "p varw" "\\$\[0-9\]* = \\( *\\( *\\( *6, *5, *1,\[()5, .\]*\\)" "p varw filled" ++# "up" works with GCC but other Fortran compilers may copy the values into the ++# outer function only on the exit of the inner function. ++gdb_test "finish" ".*call bar \\(y, x\\)" ++gdb_test "p z(2,4,5)" "\\$\[0-9\]* = 3" ++gdb_test "p z(2,4,6)" "\\$\[0-9\]* = 6" ++gdb_test "p z(2,4,7)" "\\$\[0-9\]* = 5" ++gdb_test "p z(4,4,6)" "\\$\[0-9\]* = 1" ++ ++gdb_breakpoint [gdb_get_line_number "varz-almostfilled"] ++gdb_continue_to_breakpoint "varz-almostfilled" ++# GCC uses the pointer type here, Intel Fortran Compiler 10.1.008 does not. ++gdb_test "ptype varz" "type = (PTR TO -> \\( )?real(\\(kind=4\\)|\\*4) \\(\\*\\)\\)?" ++# Intel Fortran Compiler 10.1.008 has a bug here - (2:11,7:7) ++# as it produces DW_AT_lower_bound == DW_AT_upper_bound == 7. ++gdb_test "ptype vart" "type = (PTR TO -> \\( )?real(\\(kind=4\\)|\\*4) \\(2:11,7:\\*\\)\\)?" ++gdb_test "p varz" "\\$\[0-9\]* = \\(\\)" ++gdb_test "p vart" "\\$\[0-9\]* = \\(\\)" ++gdb_test "p varz(3)" "\\$\[0-9\]* = 4" ++# maps to foo::vary(1,1) ++gdb_test "p vart(2,7)" "\\$\[0-9\]* = 8" ++# maps to foo::vary(2,2) ++gdb_test "p vart(3,8)" "\\$\[0-9\]* = 9" ++# maps to foo::vary(1,3) ++gdb_test "p vart(2,9)" "\\$\[0-9\]* = 10" ++ ++set test "quit #1" ++gdb_test_multiple "quit" $test { ++ -re "The program is running. Quit anyway \\(and kill it\\)\\? \\(y or n\\) " { ++ pass $test ++ } ++} ++set test "quit #2" ++gdb_test_multiple "y" $test { ++ eof { ++ pass $test ++ } ++} +diff --git a/gdb/testsuite/gdb.fortran/dynamic.f90 b/gdb/testsuite/gdb.fortran/dynamic.f90 +new file mode 100644 +index 0000000..0f43564 +--- /dev/null ++++ b/gdb/testsuite/gdb.fortran/dynamic.f90 +@@ -0,0 +1,98 @@ ++! Copyright 2007 Free Software Foundation, Inc. ++! ++! This program is free software; you can redistribute it and/or modify ++! it under the terms of the GNU General Public License as published by ++! the Free Software Foundation; either version 2 of the License, or ++! (at your option) any later version. ++! ++! This program is distributed in the hope that it will be useful, ++! but WITHOUT ANY WARRANTY; without even the implied warranty of ++! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++! GNU General Public License for more details. ++! ++! You should have received a copy of the GNU General Public License ++! along with this program; if not, write to the Free Software ++! Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++! ++! Ihis file is the Fortran source file for dynamic.exp. ++! Original file written by Jakub Jelinek . ++! Modified for the GDB testcase by Jan Kratochvil . ++ ++subroutine baz ++ real, target, allocatable :: varx (:, :, :) ++ real, pointer :: varv (:, :, :) ++ real, target :: varu (1, 2, 3) ++ logical :: l ++ allocate (varx (1:6, 5:15, 17:28)) ! varx-init ++ l = allocated (varx) ++ varx(:, :, :) = 6 ! varx-allocated ++ varx(1, 5, 17) = 7 ++ varx(2, 6, 18) = 8 ++ varx(6, 15, 28) = 9 ++ varv => varx ! varx-filled ++ l = associated (varv) ++ varv(3, 7, 19) = 10 ! varv-associated ++ varv => null () ! varv-filled ++ l = associated (varv) ++ deallocate (varx) ! varv-deassociated ++ l = allocated (varx) ++ varu(:, :, :) = 10 ! varx-deallocated ++ allocate (varv (1:6, 5:15, 17:28)) ++ l = associated (varv) ++ varv(:, :, :) = 6 ++ varv(1, 5, 17) = 7 ++ varv(2, 6, 18) = 8 ++ varv(6, 15, 28) = 9 ++ deallocate (varv) ++ l = associated (varv) ++ varv => varu ++ varv(1, 1, 1) = 6 ++ varv(1, 2, 3) = 7 ++ l = associated (varv) ++end subroutine baz ++subroutine foo (vary, varw) ++ real :: vary (:, :) ++ real :: varw (:, :, :) ++ vary(:, :) = 4 ! vary-passed ++ vary(1, 1) = 8 ++ vary(2, 2) = 9 ++ vary(1, 3) = 10 ++ varw(:, :, :) = 5 ! vary-filled ++ varw(1, 1, 1) = 6 ++ varw(2, 2, 2) = 7 ! varw-almostfilled ++end subroutine foo ++subroutine bar (varz, vart) ++ real :: varz (*) ++ real :: vart (2:11, 7:*) ++ varz(1:3) = 4 ++ varz(2) = 5 ! varz-almostfilled ++ vart(2,7) = vart(2,7) ++end subroutine bar ++program test ++ interface ++ subroutine foo (vary, varw) ++ real :: vary (:, :) ++ real :: varw (:, :, :) ++ end subroutine ++ end interface ++ interface ++ subroutine bar (varz, vart) ++ real :: varz (*) ++ real :: vart (2:11, 7:*) ++ end subroutine ++ end interface ++ real :: x (10, 10), y (5), z(8, 8, 8) ++ x(:,:) = 1 ++ y(:) = 2 ++ z(:,:,:) = 3 ++ call baz ++ call foo (x, z(2:6, 4:7, 6:8)) ++ call bar (y, x) ++ if (x (1, 1) .ne. 8 .or. x (2, 2) .ne. 9 .or. x (1, 2) .ne. 4) call abort ++ if (x (1, 3) .ne. 10) call abort ++ if (z (2, 4, 6) .ne. 6 .or. z (3, 5, 7) .ne. 7 .or. z (2, 4, 7) .ne. 5) call abort ++ if (any (y .ne. (/4, 5, 4, 2, 2/))) call abort ++ call foo (transpose (x), z) ++ if (x (1, 1) .ne. 8 .or. x (2, 2) .ne. 9 .or. x (1, 2) .ne. 4) call abort ++ if (x (3, 1) .ne. 10) call abort ++end +diff --git a/gdb/testsuite/gdb.fortran/logical.exp b/gdb/testsuite/gdb.fortran/logical.exp +new file mode 100644 +index 0000000..ef76f43 +--- /dev/null ++++ b/gdb/testsuite/gdb.fortran/logical.exp +@@ -0,0 +1,44 @@ ++# Copyright 2007 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++# This file was written by Jan Kratochvil . ++ ++set testfile "logical" ++set srcfile ${testfile}.f90 ++set binfile ${objdir}/${subdir}/${testfile} ++ ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug f77 quiet}] != "" } { ++ untested "Couldn't compile ${srcfile}" ++ return -1 ++} ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++if ![runto MAIN__] then { ++ perror "couldn't run to breakpoint MAIN__" ++ continue ++} ++ ++gdb_breakpoint [gdb_get_line_number "stop-here"] ++gdb_continue_to_breakpoint "stop-here" ++gdb_test "p l" " = \\.TRUE\\." ++gdb_test "p l1" " = \\.TRUE\\." ++gdb_test "p l2" " = \\.TRUE\\." ++gdb_test "p l4" " = \\.TRUE\\." ++gdb_test "p l8" " = \\.TRUE\\." +diff --git a/gdb/testsuite/gdb.fortran/logical.f90 b/gdb/testsuite/gdb.fortran/logical.f90 +new file mode 100644 +index 0000000..4229304 +--- /dev/null ++++ b/gdb/testsuite/gdb.fortran/logical.f90 +@@ -0,0 +1,33 @@ ++! Copyright 2008 Free Software Foundation, Inc. ++! ++! This program is free software; you can redistribute it and/or modify ++! it under the terms of the GNU General Public License as published by ++! the Free Software Foundation; either version 2 of the License, or ++! (at your option) any later version. ++! ++! This program is distributed in the hope that it will be useful, ++! but WITHOUT ANY WARRANTY; without even the implied warranty of ++! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++! GNU General Public License for more details. ++! ++! You should have received a copy of the GNU General Public License ++! along with this program; if not, write to the Free Software ++! Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++! ++! Ihis file is the Fortran source file for dynamic.exp. ++! Original file written by Jakub Jelinek . ++! Modified for the GDB testcase by Jan Kratochvil . ++ ++program test ++ logical :: l ++ logical (kind=1) :: l1 ++ logical (kind=2) :: l2 ++ logical (kind=4) :: l4 ++ logical (kind=8) :: l8 ++ l = .TRUE. ++ l1 = .TRUE. ++ l2 = .TRUE. ++ l4 = .TRUE. ++ l8 = .TRUE. ++ l = .FALSE. ! stop-here ++end +diff --git a/gdb/testsuite/gdb.fortran/string.exp b/gdb/testsuite/gdb.fortran/string.exp +new file mode 100644 +index 0000000..ab72206 +--- /dev/null ++++ b/gdb/testsuite/gdb.fortran/string.exp +@@ -0,0 +1,72 @@ ++# Copyright 2008 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++# This file was written by Jan Kratochvil . ++ ++# This file is part of the gdb testsuite. It contains tests for Fortran ++# strings with dynamic length. ++ ++set testfile "string" ++set srcfile ${testfile}.f90 ++set binfile ${objdir}/${subdir}/${testfile} ++ ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug f77 quiet}] != "" } { ++ untested "Couldn't compile ${srcfile}" ++ return -1 ++} ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++if ![runto MAIN__] then { ++ perror "couldn't run to breakpoint MAIN__" ++ continue ++} ++ ++gdb_breakpoint [gdb_get_line_number "var-init"] ++gdb_continue_to_breakpoint "var-init" ++gdb_test "ptype c" "type = character(\\(kind=1\\)|\\*1)" ++gdb_test "ptype d" "type = character(\\(kind=8\\)|\\*8)" ++gdb_test "ptype e" "type = character(\\(kind=4\\)|\\*4)" ++gdb_test "ptype f" "type = character(\\(kind=4\\)|\\*4) \\(7,8:10\\)" ++gdb_test "ptype *e" "Attempt to take contents of a non-pointer value." ++gdb_test "ptype *f" "type = character(\\(kind=4\\)|\\*4) \\(7\\)" ++gdb_test "p c" "\\$\[0-9\]* = 'c'" ++gdb_test "p d" "\\$\[0-9\]* = 'd '" ++gdb_test "p e" "\\$\[0-9\]* = 'g '" ++gdb_test "p f" "\\$\[0-9\]* = \\(\\( 'h ', 'h ', 'h ', 'h ', 'h ', 'h ', 'h '\\) \\( 'h ', 'h ', 'h ', 'h ', 'h ', 'h ', 'h '\\) \\( 'h ', 'h ', 'h ', 'h ', 'h ', 'h ', 'h '\\) \\)" ++gdb_test "p *e" "Attempt to take contents of a non-pointer value." ++gdb_test "p *f" "Attempt to take contents of a non-pointer value." ++ ++gdb_breakpoint [gdb_get_line_number "var-finish"] ++gdb_continue_to_breakpoint "var-finish" ++gdb_test "p e" "\\$\[0-9\]* = 'e '" "p e re-set" ++gdb_test "p f" "\\$\[0-9\]* = \\(\\( 'f ', 'f ', 'f ', 'f ', 'f ', 'f ', 'f '\\) \\( 'f2 ', 'f ', 'f ', 'f ', 'f ', 'f ', 'f '\\) \\( 'f ', 'f ', 'f ', 'f ', 'f ', 'f ', 'f '\\) \\)" "p *f re-set" ++ ++set test "quit #1" ++gdb_test_multiple "quit" $test { ++ -re "The program is running. Quit anyway \\(and kill it\\)\\? \\(y or n\\) " { ++ pass $test ++ } ++} ++set test "quit #2" ++gdb_test_multiple "y" $test { ++ eof { ++ pass $test ++ } ++} +diff --git a/gdb/testsuite/gdb.fortran/string.f90 b/gdb/testsuite/gdb.fortran/string.f90 +new file mode 100644 +index 0000000..226dc5d +--- /dev/null ++++ b/gdb/testsuite/gdb.fortran/string.f90 +@@ -0,0 +1,37 @@ ++! Copyright 2008 Free Software Foundation, Inc. ++! ++! This program is free software; you can redistribute it and/or modify ++! it under the terms of the GNU General Public License as published by ++! the Free Software Foundation; either version 2 of the License, or ++! (at your option) any later version. ++! ++! This program is distributed in the hope that it will be useful, ++! but WITHOUT ANY WARRANTY; without even the implied warranty of ++! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++! GNU General Public License for more details. ++! ++! You should have received a copy of the GNU General Public License ++! along with this program; if not, write to the Free Software ++! Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++! ++! Ihis file is the Fortran source file for dynamic.exp. ++! Original file written by Jakub Jelinek . ++! Modified for the GDB testcase by Jan Kratochvil . ++ ++subroutine foo (e, f) ++ character (len=1) :: c ++ character (len=8) :: d ++ character (len=*) :: e ++ character (len=*) :: f (1:7, 8:10) ++ c = 'c' ++ d = 'd' ++ e = 'e' ! var-init ++ f = 'f' ++ f(1,9) = 'f2' ++ c = 'c' ! var-finish ++end subroutine foo ++ character (len=4) :: g, h (1:7, 8:10) ++ g = 'g' ++ h = 'h' ++ call foo (g, h) ++end +diff --git a/gdb/testsuite/gdb.gdb/selftest.exp b/gdb/testsuite/gdb.gdb/selftest.exp +index 495ae45..d08d7a4 100644 +--- a/gdb/testsuite/gdb.gdb/selftest.exp ++++ b/gdb/testsuite/gdb.gdb/selftest.exp +@@ -95,6 +95,10 @@ proc do_steps_and_nexts {} { + set description "step over ttyarg initialization" + set command "step" + } ++ -re ".*python_script = 0.*$gdb_prompt $" { ++ set description "step over python_script initialization" ++ set command "step" ++ } + -re ".*time_at_startup = get_run_time.*$gdb_prompt $" { + set description "next over get_run_time and everything it calls" + set command "next" +diff --git a/gdb/testsuite/gdb.opt/array-from-register-func.c b/gdb/testsuite/gdb.opt/array-from-register-func.c +new file mode 100644 +index 0000000..729f457 +--- /dev/null ++++ b/gdb/testsuite/gdb.opt/array-from-register-func.c +@@ -0,0 +1,22 @@ ++/* This file is part of GDB, the GNU debugger. ++ ++ Copyright 2009 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++int ++func (int *arr) ++{ ++ return arr[0]; ++} +diff --git a/gdb/testsuite/gdb.opt/array-from-register.c b/gdb/testsuite/gdb.opt/array-from-register.c +new file mode 100644 +index 0000000..3090e7e +--- /dev/null ++++ b/gdb/testsuite/gdb.opt/array-from-register.c +@@ -0,0 +1,28 @@ ++/* This file is part of GDB, the GNU debugger. ++ ++ Copyright 2009 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++extern int func (int *arr); ++ ++int ++main (void) ++{ ++ int arr[] = { 42 }; ++ ++ func (arr); ++ ++ return 0; ++} +diff --git a/gdb/testsuite/gdb.opt/array-from-register.exp b/gdb/testsuite/gdb.opt/array-from-register.exp +new file mode 100644 +index 0000000..f2de718 +--- /dev/null ++++ b/gdb/testsuite/gdb.opt/array-from-register.exp +@@ -0,0 +1,33 @@ ++# Copyright 2009 Free Software Foundation, Inc. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++# ++# This file is part of the gdb testsuite. ++ ++if { [prepare_for_testing array-from-register.exp "array-from-register" \ ++ {array-from-register.c array-from-register-func.c} \ ++ {debug optimize=-O2}] } { ++ return -1 ++} ++ ++if ![runto func] then { ++ return -1 ++} ++ ++gdb_test "p arr" "\\$\[0-9\]+ = \\(int \\*\\) *0x\[0-9a-f\]+" ++ ++# Seen regression: ++# Address requested for identifier "arr" which is in register $rdi ++gdb_test "p arr\[0\]" "\\$\[0-9\]+ = 42" +diff --git a/gdb/testsuite/gdb.python/Makefile.in b/gdb/testsuite/gdb.python/Makefile.in +index 79be9e7..c49f713 100644 +--- a/gdb/testsuite/gdb.python/Makefile.in ++++ b/gdb/testsuite/gdb.python/Makefile.in +@@ -1,7 +1,7 @@ + VPATH = @srcdir@ + srcdir = @srcdir@ + +-EXECUTABLES = python-value ++EXECUTABLES = python-value python-prettyprint python-template + + all info install-info dvi install uninstall installcheck check: + @echo "Nothing to be done for $@..." +diff --git a/gdb/testsuite/gdb.python/find.c b/gdb/testsuite/gdb.python/find.c +new file mode 100644 +index 0000000..35ddd8c +--- /dev/null ++++ b/gdb/testsuite/gdb.python/find.c +@@ -0,0 +1,64 @@ ++/* Testcase for the search_memory Python function. ++ This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2009 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++ Please email any bugs, comments, and/or additions to this file to: ++ bug-gdb@gnu.org */ ++ ++/* Based on the gdb.base/find.c testcase. */ ++ ++#include ++#include ++ ++#define CHUNK_SIZE 16000 /* same as findcmd.c's */ ++#define BUF_SIZE (2 * CHUNK_SIZE) /* at least two chunks */ ++ ++static int8_t int8_search_buf[100]; ++static int16_t int16_search_buf[100]; ++static int32_t int32_search_buf[100]; ++static int64_t int64_search_buf[100]; ++ ++static char *search_buf; ++static int search_buf_size; ++ ++static int x; ++ ++static void ++stop_here () ++{ ++ x = 1; // stop here ++} ++ ++static void ++init_bufs () ++{ ++ search_buf_size = BUF_SIZE; ++ search_buf = malloc (search_buf_size); ++ if (search_buf == NULL) ++ exit (1); ++ memset (search_buf, 'x', search_buf_size); ++} ++ ++int ++main () ++{ ++ init_bufs (); ++ ++ stop_here (); ++ ++ return 0; ++} +diff --git a/gdb/testsuite/gdb.python/find.exp b/gdb/testsuite/gdb.python/find.exp +new file mode 100644 +index 0000000..dd9aabc +--- /dev/null ++++ b/gdb/testsuite/gdb.python/find.exp +@@ -0,0 +1,203 @@ ++# Copyright 2008, 2009 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++# This tests the search_memory Python function. ++# Based on the gdb.base/find.exp testcase. ++ ++if $tracelevel then { ++ strace $tracelevel ++} ++ ++# Usage: gdb_py_test_multiple NAME INPUT RESULT {INPUT RESULT}... ++# Run a test named NAME, consisting of multiple lines of input. ++# After each input line INPUT, search for result line RESULT. ++# Succeed if all results are seen; fail otherwise. ++proc gdb_py_test_multiple {name args} { ++ global gdb_prompt ++ foreach {input result} $args { ++ if {[gdb_test_multiple $input "$name - $input" { ++ -re "\[\r\n\]*($result)\[\r\n\]+($gdb_prompt | *>)$" { ++ pass "$name - $input" ++ } ++ }]} { ++ return 1 ++ } ++ } ++ return 0 ++} ++ ++set testfile "find" ++set srcfile ${testfile}.c ++set binfile ${objdir}/${subdir}/${testfile} ++ ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug nowarnings}] != "" } { ++ untested find.exp ++ return -1 ++} ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++gdb_test_multiple "python print 'hello, world!'" "verify python support" { ++ -re "not supported.*$gdb_prompt $" { ++ unsupported "python support is disabled" ++ return -1 ++ } ++ -re "$gdb_prompt $" {} ++} ++ ++gdb_test "break $srcfile:stop_here" \ ++ "Breakpoint.*at.* file .*$srcfile, line.*" \ ++ "breakpoint function in file" ++ ++gdb_run_cmd ++gdb_expect { ++ -re "Breakpoint \[0-9\]+,.*stop_here.* at .*$srcfile:.*$gdb_prompt $" { ++ pass "run until function breakpoint" ++ } ++ -re "$gdb_prompt $" { ++ fail "run until function breakpoint" ++ } ++ timeout { ++ fail "run until function breakpoint (timeout)" ++ } ++} ++ ++# We've now got the target program in a state where we can test "find". ++ ++set hex_number {0x[0-9a-fA-F][0-9a-fA-F]*} ++set dec_number {[0-9]+} ++set history_prefix {[$][0-9]* = } ++set newline {[\r\n]+} ++set pattern_not_found "${newline}.]" ++set one_pattern_found "${newline}.${dec_number}L]" ++set two_patterns_found "${newline}.${dec_number}L, ${dec_number}L]" ++ ++# Test string pattern. ++ ++gdb_test "set *(int32_t*) &int8_search_buf\[10\] = 0x61616161" "" "" ++gdb_test "py search_buf = gdb.selected_frame ().read_var ('int8_search_buf')" "" "" ++gdb_test "py start_addr = search_buf.address ()" "" "" ++gdb_test "py length = search_buf.type ().sizeof ()" "" "" ++ ++gdb_test "py print gdb.search_memory (start_addr, length, 'aaa')" \ ++ "${two_patterns_found}" "find string pattern" ++ ++# Test not finding pattern because search range too small, with ++# potential find at the edge of the range. ++ ++gdb_test "py print gdb.search_memory (start_addr, 10+3, 'aaaa')" \ ++ "${pattern_not_found}" "pattern not found at end of range" ++ ++# Increase the search range by 1 and we should find the pattern. ++ ++gdb_test "py print gdb.search_memory (start_addr, 10+3+1, \['a', 'a', 'a', 'a'\])" \ ++ "${one_pattern_found}" "pattern found at end of range" ++ ++# Test max-count with size, with different parameter position ++ ++gdb_test "py print gdb.search_memory (start_addr, length, \[0x61, 0x61\], 1, 1)" \ ++ "${one_pattern_found}" "size = 1, max_count = 1" ++ ++gdb_test "py print gdb.search_memory (start_addr, length, \[0x61, 0x61\], 1, 2)" \ ++ "${two_patterns_found}" "size = 1, max_count = 2, normal ordering" ++ ++gdb_test "py print gdb.search_memory (start_addr, length, \[0x61, 0x61\], size = 1, max_count = 2)" \ ++ "${two_patterns_found}" "size = 1, max_count = 2, normal ordering, with keywords" ++ ++gdb_test "py print gdb.search_memory (start_addr, length, \[0x61, 0x61\], max_count = 2, size = 1)" \ ++ "${two_patterns_found}" "size = 1, max_count = 2, inverted ordering" ++ ++gdb_test "py print gdb.search_memory (start_addr, length, \['a', 'a'\], max_count = 2)" \ ++ "${two_patterns_found}" "max_count = 2, with keyword" ++ ++# Test 16-bit pattern. ++ ++gdb_test "set int16_search_buf\[10\] = 0x1234" "" "" ++gdb_test "py search_buf = gdb.selected_frame ().read_var ('int16_search_buf')" "" "" ++gdb_test "py start_addr = search_buf.address ()" "" "" ++gdb_test "py length = search_buf.type ().sizeof ()" "" "" ++gdb_test "py pattern = gdb.parse_and_eval ('(int16_t) 0x1234')" "" "" ++ ++gdb_test "py print gdb.search_memory (start_addr, length, 0x1234, 2)" \ ++ "${one_pattern_found}" "find 16-bit pattern, with python pattern" ++ ++gdb_test "py print gdb.search_memory (start_addr, length, pattern)" \ ++ "${one_pattern_found}" "find 16-bit pattern, with value pattern" ++ ++# Test 32-bit pattern. ++ ++gdb_test "set int32_search_buf\[10\] = 0x12345678" "" "" ++gdb_test "py search_buf = gdb.selected_frame ().read_var ('int32_search_buf')" "" "" ++gdb_test "py start_addr = search_buf.address ()" "" "" ++gdb_test "py length = search_buf.type ().sizeof ()" "" "" ++gdb_test "py pattern = gdb.parse_and_eval ('(int32_t) 0x12345678')" "" "" ++ ++gdb_test "py print gdb.search_memory (start_addr, length, 0x12345678, 4)" \ ++ "${one_pattern_found}" "find 32-bit pattern, with python pattern" ++gdb_test "py print gdb.search_memory (start_addr, length, pattern)" \ ++ "${one_pattern_found}" "find 32-bit pattern, with value pattern" ++ ++# Test 64-bit pattern. ++ ++gdb_test "set int64_search_buf\[10\] = 0xfedcba9876543210LL" "" "" ++gdb_test "py search_buf = gdb.selected_frame ().read_var ('int64_search_buf')" "" "" ++gdb_test "py start_addr = search_buf.address ()" "" "" ++gdb_test "py length = search_buf.type ().sizeof ()" "" "" ++gdb_test "py pattern = gdb.parse_and_eval ('(int64_t) 0xfedcba9876543210LL')" "" "" ++ ++gdb_test "py print gdb.search_memory (start_addr, length, 0xfedcba9876543210, 8)" \ ++ "${one_pattern_found}" "find 64-bit pattern, with python pattern" ++gdb_test "py print gdb.search_memory (start_addr, length, pattern)" \ ++ "${one_pattern_found}" "find 64-bit pattern, with value pattern" ++ ++# Test mixed-sized patterns. ++ ++gdb_test "set *(int8_t*) &search_buf\[10\] = 0x62" "" "" ++gdb_test "set *(int16_t*) &search_buf\[11\] = 0x6363" "" "" ++gdb_test "set *(int32_t*) &search_buf\[13\] = 0x64646464" "" "" ++gdb_test "py search_buf = gdb.selected_frame ().read_var ('search_buf')" "" "" ++gdb_test "py start_addr = search_buf\[0\].address ()" "" "" ++gdb_test "py pattern1 = gdb.parse_and_eval ('(int8_t) 0x62')" "" "" ++gdb_test "py pattern2 = gdb.parse_and_eval ('(int16_t) 0x6363')" "" "" ++gdb_test "py pattern3 = gdb.parse_and_eval ('(int32_t) 0x64646464')" "" "" ++ ++gdb_test "py print gdb.search_memory (start_addr, 100, \[pattern1, pattern2, pattern3\])" \ ++ "${one_pattern_found}" "find mixed-sized pattern" ++ ++# Test search spanning a large range, in the particular case of native ++# targets, test the search spanning multiple chunks. ++# Remote targets may implement the search differently. ++ ++set CHUNK_SIZE 16000 ; ++ ++gdb_test "set *(int32_t*) &search_buf\[0*${CHUNK_SIZE}+100\] = 0x12345678" "" "" ++gdb_test "set *(int32_t*) &search_buf\[1*${CHUNK_SIZE}+100\] = 0x12345678" "" "" ++gdb_test "py start_addr = gdb.selected_frame ().read_var ('search_buf')" "" "" ++gdb_test "py length = gdb.selected_frame ().read_var ('search_buf_size')" "" "" ++ ++gdb_test "py print gdb.search_memory (start_addr, length, 0x12345678, 4)" \ ++ "${two_patterns_found}" "search spanning large range" ++ ++# For native targets, test a pattern straddling a chunk boundary. ++ ++if [isnative] { ++ gdb_test "set *(int32_t*) &search_buf\[${CHUNK_SIZE}-1\] = 0xfdb97531" "" "" ++ ++ gdb_test "py print gdb.search_memory (start_addr, length, 0xfdb97531, 4)" \ ++ "${one_pattern_found}" "find pattern straddling chunk boundary" ++} +diff --git a/gdb/testsuite/gdb.python/python-cmd.exp b/gdb/testsuite/gdb.python/python-cmd.exp +index 6c73ff2..f6ef938 100644 +--- a/gdb/testsuite/gdb.python/python-cmd.exp ++++ b/gdb/testsuite/gdb.python/python-cmd.exp +@@ -92,6 +92,32 @@ gdb_py_test_multiple "input subcommand" \ + + gdb_test "prefix_cmd subcmd ugh" "subcmd output, arg = ugh" "call subcmd" + ++# Test prefix command using keyword arguments. ++ ++gdb_py_test_multiple "input prefix command, keyword arguments" \ ++ "python" "" \ ++ "class prefix_cmd2 (gdb.Command):" "" \ ++ " def __init__ (self):" "" \ ++ " super (prefix_cmd2, self).__init__ (\"prefix_cmd2\", gdb.COMMAND_OBSCURE, prefix = True, completer_class = gdb.COMPLETE_FILENAME)" "" \ ++ " def invoke (self, arg, from_tty):" "" \ ++ " print \"prefix_cmd2 output, arg = %s\" % arg" "" \ ++ "prefix_cmd2 ()" "" \ ++ "end" "" ++ ++gdb_test "prefix_cmd2 argh" "prefix_cmd2 output, arg = argh" "call prefix command, keyword arguments" ++ ++gdb_py_test_multiple "input subcommand under prefix_cmd2" \ ++ "python" "" \ ++ "class subcmd (gdb.Command):" "" \ ++ " def __init__ (self):" "" \ ++ " super (subcmd, self).__init__ (\"prefix_cmd2 subcmd\", gdb.COMMAND_OBSCURE)" "" \ ++ " def invoke (self, arg, from_tty):" "" \ ++ " print \"subcmd output, arg = %s\" % arg" "" \ ++ "subcmd ()" "" \ ++ "end" "" ++ ++gdb_test "prefix_cmd2 subcmd ugh" "subcmd output, arg = ugh" "call subcmd under prefix_cmd2" ++ + # Test a subcommand in an existing GDB prefix. + + gdb_py_test_multiple "input new subcommand" \ +diff --git a/gdb/testsuite/gdb.python/python-frame.c b/gdb/testsuite/gdb.python/python-frame.c +new file mode 100644 +index 0000000..22eb9f2 +--- /dev/null ++++ b/gdb/testsuite/gdb.python/python-frame.c +@@ -0,0 +1,14 @@ ++int f2 (int a) ++{ ++ return ++a; ++} ++ ++int f1 (int a, int b) ++{ ++ return f2(a) + b; ++} ++ ++int main (int argc, char *argv[]) ++{ ++ return f1 (1, 2); ++} +diff --git a/gdb/testsuite/gdb.python/python-frame.exp b/gdb/testsuite/gdb.python/python-frame.exp +new file mode 100644 +index 0000000..674c25e +--- /dev/null ++++ b/gdb/testsuite/gdb.python/python-frame.exp +@@ -0,0 +1,92 @@ ++# Copyright (C) 2009 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++# This file is part of the GDB testsuite. It tests the mechanism ++# exposing values to Python. ++ ++if $tracelevel then { ++ strace $tracelevel ++} ++ ++set testfile "python-frame" ++set srcfile ${testfile}.c ++set binfile ${objdir}/${subdir}/${testfile} ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { ++ untested "Couldn't compile ${srcfile}" ++ return -1 ++} ++ ++# Run a command in GDB, and report a failure if a Python exception is thrown. ++# If report_pass is true, report a pass if no exception is thrown. ++proc gdb_py_test_silent_cmd {cmd name report_pass} { ++ global gdb_prompt ++ ++ gdb_test_multiple $cmd $name { ++ -re "Traceback.*$gdb_prompt $" { fail $name } ++ -re "$gdb_prompt $" { if $report_pass { pass $name } } ++ } ++} ++ ++# Start with a fresh gdb. ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++gdb_test_multiple "python print 'hello, world!'" "verify python support" { ++ -re "not supported.*$gdb_prompt $" { ++ unsupported "python support is disabled" ++ return -1 ++ } ++ -re "$gdb_prompt $" {} ++} ++ ++# The following tests require execution. ++ ++if ![runto_main] then { ++ fail "Can't run to main" ++ return 0 ++} ++ ++gdb_breakpoint "f2" ++gdb_continue_to_breakpoint "breakpoint at f2" ++gdb_test "up" "" "" ++ ++gdb_py_test_silent_cmd "python frames = gdb.frames ()" "get frames list" 1 ++gdb_test "python print frames" "\\(, , \\)" "verify frames list" ++gdb_py_test_silent_cmd "python f0 = frames\[0\]" "get first frame" 0 ++gdb_py_test_silent_cmd "python f1 = frames\[1\]" "get second frame" 0 ++ ++gdb_test "python print 'result =', f0.equals (f1)" " = False" "test equals (false)" ++gdb_test "python print 'result =', f0.equals (f0)" " = True" "test equals (true)" ++gdb_test "python print 'result =', f0.is_valid ()" " = True" "test Frame.is_valid" ++gdb_test "python print 'result =', f0.name ()" " = f2" "test Frame.name" ++gdb_test "python print 'result =', f0.type () == gdb.NORMAL_FRAME" " = True" "test Frame.type" ++gdb_test "python print 'result =', f0.unwind_stop_reason () == gdb.FRAME_UNWIND_NO_REASON" " = True" "test Frame.type" ++gdb_test "python print 'result =', gdb.frame_stop_reason_string (gdb.FRAME_UNWIND_INNER_ID)" " = previous frame inner to this frame \\(corrupt stack\\?\\)" "test gdb.frame_stop_reason_string" ++gdb_test "python print 'result =', f0.pc ()" " = \[0-9\]+" "test Frame.pc" ++gdb_test "python print 'result =', f0.addr_in_block ()" " = \[0-9\]+" "test Frame.addr_in_block" ++gdb_test "python print 'result =', f0.older ().equals (f1)" " = True" "test Frame.older" ++gdb_test "python print 'result =', f1.newer ().equals (f0)" " = True" "test Frame.newer" ++gdb_test "python print 'result =', f0.read_var ('variable_which_surely_doesnt_exist')" \ ++ "ValueError: variable 'variable_which_surely_doesnt_exist' not found.*Error while executing Python code." \ ++ "test Frame.read_var - error" ++gdb_test "python print 'result =', f0.read_var ('a')" " = 1" "test Frame.read_var - success" ++ ++gdb_test "python print 'result =', gdb.newest_frame ().equals (f0)" " = True" "test gdb.newest_frame" ++gdb_test "python print 'result =', gdb.selected_frame ().equals (f1)" " = True" "test gdb.selected_frame" ++ ++gdb_test "python print 'result =', f0.block ()" "" "test Frame.block" +diff --git a/gdb/testsuite/gdb.python/python-function.exp b/gdb/testsuite/gdb.python/python-function.exp +new file mode 100644 +index 0000000..7feca2b +--- /dev/null ++++ b/gdb/testsuite/gdb.python/python-function.exp +@@ -0,0 +1,79 @@ ++# Copyright (C) 2009 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++# This file is part of the GDB testsuite. It tests the mechanism ++# exposing convenience functions to Python. ++ ++if $tracelevel then { ++ strace $tracelevel ++} ++ ++# Usage: gdb_py_test_multiple NAME INPUT RESULT {INPUT RESULT}... ++# Run a test named NAME, consisting of multiple lines of input. ++# After each input line INPUT, search for result line RESULT. ++# Succeed if all results are seen; fail otherwise. ++proc gdb_py_test_multiple {name args} { ++ global gdb_prompt ++ foreach {input result} $args { ++ if {[gdb_test_multiple $input "$name - $input" { ++ -re "\[\r\n\]*($result)\[\r\n\]+($gdb_prompt | *>)$" { ++ pass "$name - $input" ++ } ++ }]} { ++ return 1 ++ } ++ } ++ return 0 ++} ++ ++# Start with a fresh gdb. ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++ ++gdb_test_multiple "python print 'hello, world!'" "verify python support" { ++ -re "not supported.*$gdb_prompt $" { ++ unsupported "python support is disabled" ++ return -1 ++ } ++ -re "$gdb_prompt $" {} ++} ++ ++gdb_py_test_multiple "input convenience function" \ ++ "python" "" \ ++ "class test_func (gdb.Function):" "" \ ++ " def __init__ (self):" "" \ ++ " super (test_func, self).__init__ (\"test_func\")" "" \ ++ " def invoke (self, arg):" "" \ ++ " return \"test_func output, arg = %s\" % arg.string ()" "" \ ++ "test_func ()" "" \ ++ "end" "" ++ ++gdb_test "print \$test_func (\"ugh\")" "= \"test_func output, arg = ugh\"" "call function" ++ ++# Test returning a gdb.Value from the function. This segfaulted GDB at one point. ++ ++gdb_py_test_multiple "input value-returning convenience function" \ ++ "python" "" \ ++ "class Double (gdb.Function):" "" \ ++ " def __init__ (self):" "" \ ++ " super (Double, self).__init__ (\"double\")" "" \ ++ " def invoke (self, n):" "" \ ++ " return n*2" "" \ ++ "Double ()" "" \ ++ "end" "" ++ ++gdb_test "print \$double (1)" "= 2" "call value-returning function" +diff --git a/gdb/testsuite/gdb.python/python-mi.exp b/gdb/testsuite/gdb.python/python-mi.exp +new file mode 100644 +index 0000000..5c9f3c7 +--- /dev/null ++++ b/gdb/testsuite/gdb.python/python-mi.exp +@@ -0,0 +1,124 @@ ++# Copyright (C) 2008 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++# This file is part of the GDB testsuite. It tests Python-based ++# pretty-printing for MI. ++ ++load_lib mi-support.exp ++set MIFLAGS "-i=mi2" ++ ++gdb_exit ++if [mi_gdb_start] { ++ continue ++} ++ ++set testfile "python-prettyprint" ++set srcfile ${testfile}.c ++set binfile ${objdir}/${subdir}/${testfile} ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug additional_flags=-DMI}] != "" } { ++ untested mi2-var-child.exp ++ return -1 ++} ++ ++mi_delete_breakpoints ++mi_gdb_reinitialize_dir $srcdir/$subdir ++mi_gdb_load ${binfile} ++ ++if {[lsearch -exact [mi_get_features] python] < 0} { ++ unsupported "python support is disabled" ++ return -1 ++} ++ ++mi_runto main ++ ++mi_gdb_test "python execfile ('${srcdir}/${subdir}/${testfile}.py')" "" ++ ++mi_continue_to_line [gdb_get_line_number {MI breakpoint here} ${testfile}.c] \ ++ "step to breakpoint" ++ ++mi_create_floating_varobj container c "create container varobj" ++ ++mi_list_varobj_children container { ++} "examine container children=0" ++ ++mi_next "next over update 1" ++ ++mi_varobj_update_dynamic container { ++ { {container.\[0\]} {\[0\]} 0 int } ++} "varobj update 1" ++ ++mi_next "next over update 2" ++ ++mi_varobj_update_dynamic container { ++ { {container.\[0\]} {\[0\]} 0 int } ++ { {container.\[1\]} {\[1\]} 0 int } ++} "varobj update 2" ++ ++mi_gdb_test "-var-set-visualizer container None" \ ++ "\\^done" \ ++ "clear visualizer" ++ ++mi_gdb_test "-var-update container" \ ++ "\\^done,changelist=\\\[\\\]" \ ++ "varobj update after clearing" ++ ++mi_gdb_test "-var-set-visualizer container gdb.default_visualizer" \ ++ "\\^done" \ ++ "choose default visualizer" ++ ++mi_varobj_update_dynamic container { ++ { {container.\[0\]} {\[0\]} 0 int } ++ { {container.\[1\]} {\[1\]} 0 int } ++} "varobj update after choosing default" ++ ++mi_gdb_test "-var-set-visualizer container ContainerPrinter" \ ++ "\\^done" \ ++ "choose visualizer using expression" ++ ++mi_varobj_update_dynamic container { ++ { {container.\[0\]} {\[0\]} 0 int } ++ { {container.\[1\]} {\[1\]} 0 int } ++} "varobj update after choosing via expression" ++ ++mi_gdb_test "-var-set-child-range container 1 2" \ ++ "\\^done" \ ++ "select child range" ++ ++mi_gdb_test "-var-update container" \ ++ "\\^done,changelist=\\\[\\\]" \ ++ "varobj update after selecting child range" ++ ++mi_list_varobj_children_range container 2 { ++ { {container.\[1\]} {\[1\]} 0 int } ++} "list varobj children after selecting child range" ++ ++mi_gdb_test "-var-set-child-range container -1 -1" \ ++ "\\^done" \ ++ "reset child range" ++ ++mi_gdb_test "-var-update container" \ ++ "\\^done,changelist=\\\[\\\]" \ ++ "varobj update after resetting child range" ++ ++mi_list_varobj_children container { ++ { {container.\[0\]} {\[0\]} 0 int } ++ { {container.\[1\]} {\[1\]} 0 int } ++} "list varobj children after resetting child range" ++ ++mi_continue_to_line \ ++ [gdb_get_line_number {Another MI breakpoint} ${testfile}.c] \ ++ "step to second breakpoint" ++ ++mi_varobj_update_with_type_change container int 0 "update after type change" +diff --git a/gdb/testsuite/gdb.python/python-prettyprint.c b/gdb/testsuite/gdb.python/python-prettyprint.c +new file mode 100644 +index 0000000..f8c2435 +--- /dev/null ++++ b/gdb/testsuite/gdb.python/python-prettyprint.c +@@ -0,0 +1,159 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2008 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++struct s ++{ ++ int a; ++ int *b; ++}; ++ ++struct ss ++{ ++ struct s a; ++ struct s b; ++}; ++ ++#ifdef __cplusplus ++struct S : public s { ++ int zs; ++}; ++ ++struct SS { ++ int zss; ++ S s; ++}; ++ ++struct SSS ++{ ++ SSS (int x, const S& r); ++ int a; ++ const S &b; ++}; ++SSS::SSS (int x, const S& r) : a(x), b(r) { } ++#endif ++ ++typedef struct string_repr ++{ ++ struct whybother ++ { ++ const char *contents; ++ } whybother; ++} string; ++ ++/* This lets us avoid malloc. */ ++int array[100]; ++ ++struct container ++{ ++ string name; ++ int len; ++ int *elements; ++}; ++ ++typedef struct container zzz_type; ++ ++string ++make_string (const char *s) ++{ ++ string result; ++ result.whybother.contents = s; ++ return result; ++} ++ ++zzz_type ++make_container (const char *s) ++{ ++ zzz_type result; ++ ++ result.name = make_string (s); ++ result.len = 0; ++ result.elements = 0; ++ ++ return result; ++} ++ ++void ++add_item (zzz_type *c, int val) ++{ ++ if (c->len == 0) ++ c->elements = array; ++ c->elements[c->len] = val; ++ ++c->len; ++} ++ ++void init_s(struct s *s, int a) ++{ ++ s->a = a; ++ s->b = &s->a; ++} ++ ++void init_ss(struct ss *s, int a, int b) ++{ ++ init_s(&s->a, a); ++ init_s(&s->b, b); ++} ++ ++void do_nothing(void) ++{ ++ int c; ++ ++ c = 23; /* Another MI breakpoint */ ++} ++ ++int ++main () ++{ ++ struct ss ss; ++ struct ss ssa[2]; ++ string x = make_string ("this is x"); ++ zzz_type c = make_container ("container"); ++ const struct string_repr cstring = { { "const string" } }; ++ ++ init_ss(&ss, 1, 2); ++ init_ss(ssa+0, 3, 4); ++ init_ss(ssa+1, 5, 6); ++ ++#ifdef __cplusplus ++ S cps; ++ ++ cps.zs = 7; ++ init_s(&cps, 8); ++ ++ SS cpss; ++ cpss.zss = 9; ++ init_s(&cpss.s, 10); ++ ++ SS cpssa[2]; ++ cpssa[0].zss = 11; ++ init_s(&cpssa[0].s, 12); ++ cpssa[1].zss = 13; ++ init_s(&cpssa[1].s, 14); ++ ++ SSS sss(15, cps); ++ ++ SSS& ref (sss); ++#endif ++ ++ add_item (&c, 23); /* MI breakpoint here */ ++ add_item (&c, 72); ++ ++#ifdef MI ++ do_nothing (); ++#endif ++ ++ return 0; /* break to inspect struct and union */ ++} +diff --git a/gdb/testsuite/gdb.python/python-prettyprint.exp b/gdb/testsuite/gdb.python/python-prettyprint.exp +new file mode 100644 +index 0000000..b2ccb2b +--- /dev/null ++++ b/gdb/testsuite/gdb.python/python-prettyprint.exp +@@ -0,0 +1,90 @@ ++# Copyright (C) 2008 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++# This file is part of the GDB testsuite. It tests Python-based ++# pretty-printing for the CLI. ++ ++if $tracelevel then { ++ strace $tracelevel ++} ++ ++set testfile "python-prettyprint" ++set srcfile ${testfile}.c ++set binfile ${objdir}/${subdir}/${testfile} ++ ++# Start with a fresh gdb. ++gdb_exit ++gdb_start ++gdb_test_multiple "python print 'hello, world!'" "verify python support" { ++ -re "not supported.*$gdb_prompt $" { ++ unsupported "python support is disabled" ++ return -1 ++ } ++ -re "$gdb_prompt $" {} ++} ++ ++proc run_lang_tests {lang} { ++ global srcdir subdir srcfile binfile testfile hex ++ if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable "debug $lang"] != "" } { ++ untested "Couldn't compile ${srcfile} in $lang mode" ++ return -1 ++ } ++ ++ set nl "\[\r\n\]+" ++ ++ # Start with a fresh gdb. ++ gdb_exit ++ gdb_start ++ gdb_reinitialize_dir $srcdir/$subdir ++ gdb_load ${binfile} ++ ++ ++ if ![runto_main ] then { ++ perror "couldn't run to breakpoint" ++ return ++ } ++ ++ gdb_test "set print pretty on" "" ++ ++ gdb_test "b [gdb_get_line_number {break to inspect} ${testfile}.c ]" \ ++ ".*Breakpoint.*" ++ gdb_test "continue" ".*Breakpoint.*" ++ ++ gdb_test "python execfile ('${srcdir}/${subdir}/${testfile}.py')" "" ++ ++ gdb_test "print ss" " = a=< a=<1> b=<$hex>> b=< a=<2> b=<$hex>>" ++ gdb_test "print ssa\[1\]" " = a=< a=<5> b=<$hex>> b=< a=<6> b=<$hex>>" ++ gdb_test "print ssa" " = {a=< a=<3> b=<$hex>> b=< a=<4> b=<$hex>>, a=< a=<5> b=<$hex>> b=< a=<6> b=<$hex>>}" ++ ++ if {$lang == "c++"} { ++ gdb_test "print cps" "= a=<8> b=<$hex>" ++ gdb_test "print cpss" " = {$nl *zss = 9, *$nl *s = a=<10> b=<$hex>$nl}" ++ gdb_test "print cpssa\[0\]" " = {$nl *zss = 11, *$nl *s = a=<12> b=<$hex>$nl}" ++ gdb_test "print cpssa\[1\]" " = {$nl *zss = 13, *$nl *s = a=<14> b=<$hex>$nl}" ++ gdb_test "print cpssa" " = {{$nl *zss = 11, *$nl *s = a=<12> b=<$hex>$nl *}, {$nl *zss = 13, *$nl *s = a=<14> b=<$hex>$nl *}}" ++ gdb_test "print sss" "= a=<15> b=< a=<8> b=<$hex>>" ++ gdb_test "print ref" "= a=<15> b=< a=<8> b=<$hex>>" ++ } ++ ++ gdb_test "print x" " = $hex \"this is x\"" ++ gdb_test "print cstring" " = $hex \"const string\"" ++ ++ gdb_test "print c" " = container $hex \"container\" with 2 elements = {$nl *.0. = 23,$nl *.1. = 72$nl}" ++ ++ gdb_test "continue" "Program exited normally\." ++} ++ ++run_lang_tests "c" ++run_lang_tests "c++" +diff --git a/gdb/testsuite/gdb.python/python-prettyprint.py b/gdb/testsuite/gdb.python/python-prettyprint.py +new file mode 100644 +index 0000000..0d9cb87 +--- /dev/null ++++ b/gdb/testsuite/gdb.python/python-prettyprint.py +@@ -0,0 +1,134 @@ ++# Copyright (C) 2008, 2009 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++# This file is part of the GDB testsuite. It tests python pretty ++# printers. ++ ++import re ++ ++# Test returning a Value from a printer. ++class string_print: ++ def __init__(self, val): ++ self.val = val ++ ++ def to_string(self): ++ return self.val['whybother']['contents'] ++ ++# Test a class-based printer. ++class ContainerPrinter: ++ class _iterator: ++ def __init__ (self, pointer, len): ++ self.start = pointer ++ self.pointer = pointer ++ self.end = pointer + len ++ ++ def __iter__(self): ++ return self ++ ++ def next(self): ++ if self.pointer == self.end: ++ raise StopIteration ++ result = self.pointer ++ self.pointer = self.pointer + 1 ++ return ('[%d]' % int (result - self.start), result.dereference()) ++ ++ def __init__(self, val): ++ self.val = val ++ ++ def to_string(self): ++ return 'container %s with %d elements' % (self.val['name'], self.val['len']) ++ ++ def children(self): ++ return self._iterator(self.val['elements'], self.val['len']) ++ ++class pp_s: ++ def __init__(self, val): ++ self.val = val ++ ++ def to_string(self): ++ a = self.val["a"] ++ b = self.val["b"] ++ if a.address() != b: ++ raise Exception("&a(%s) != b(%s)" % (str(a.address()), str(b))) ++ return " a=<" + str(self.val["a"]) + "> b=<" + str(self.val["b"]) + ">" ++ ++class pp_ss: ++ def __init__(self, val): ++ self.val = val ++ ++ def to_string(self): ++ return "a=<" + str(self.val["a"]) + "> b=<" + str(self.val["b"]) + ">" ++ ++class pp_sss: ++ def __init__(self, val): ++ self.val = val ++ ++ def to_string(self): ++ return "a=<" + str(self.val['a']) + "> b=<" + str(self.val["b"]) + ">" ++ ++def lookup_function (val): ++ "Look-up and return a pretty-printer that can print val." ++ ++ # Get the type. ++ type = val.type (); ++ ++ # If it points to a reference, get the reference. ++ if type.code () == gdb.TYPE_CODE_REF: ++ type = type.target () ++ ++ # Get the unqualified type, stripped of typedefs. ++ type = type.unqualified ().strip_typedefs () ++ ++ # Get the type name. ++ typename = type.tag () ++ ++ if typename == None: ++ return None ++ ++ # Iterate over local dictionary of types to determine ++ # if a printer is registered for that type. Return an ++ # instantiation of the printer if found. ++ for function in pretty_printers_dict: ++ if function.match (typename): ++ return pretty_printers_dict[function] (val) ++ ++ # Cannot find a pretty printer. Return None. ++ ++ return None ++ ++ ++def register_pretty_printers (): ++ pretty_printers_dict[re.compile ('^struct s$')] = pp_s ++ pretty_printers_dict[re.compile ('^s$')] = pp_s ++ pretty_printers_dict[re.compile ('^S$')] = pp_s ++ ++ pretty_printers_dict[re.compile ('^struct ss$')] = pp_ss ++ pretty_printers_dict[re.compile ('^ss$')] = pp_ss ++ pretty_printers_dict[re.compile ('^const S &$')] = pp_s ++ pretty_printers_dict[re.compile ('^SSS$')] = pp_sss ++ ++ # Note that we purposely omit the typedef names here. ++ # Printer lookup is based on canonical name. ++ # However, we do need both tagged and untagged variants, to handle ++ # both the C and C++ cases. ++ pretty_printers_dict[re.compile ('^struct string_repr$')] = string_print ++ pretty_printers_dict[re.compile ('^struct container$')] = ContainerPrinter ++ pretty_printers_dict[re.compile ('^string_repr$')] = string_print ++ pretty_printers_dict[re.compile ('^container$')] = ContainerPrinter ++ ++pretty_printers_dict = {} ++ ++register_pretty_printers () ++gdb.pretty_printers.append (lookup_function) +diff --git a/gdb/testsuite/gdb.python/python-template.cc b/gdb/testsuite/gdb.python/python-template.cc +new file mode 100644 +index 0000000..bd6a212 +--- /dev/null ++++ b/gdb/testsuite/gdb.python/python-template.cc +@@ -0,0 +1,30 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2008 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++template ++struct Foo { ++}; ++ ++#ifndef TYPE ++#define TYPE int ++#endif ++ ++int main() ++{ ++ Foo foo; ++ return 0; // break here ++} +diff --git a/gdb/testsuite/gdb.python/python-template.exp b/gdb/testsuite/gdb.python/python-template.exp +new file mode 100644 +index 0000000..561ff73 +--- /dev/null ++++ b/gdb/testsuite/gdb.python/python-template.exp +@@ -0,0 +1,75 @@ ++# Copyright (C) 2008 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++# This file is part of the GDB testsuite. It tests the mechanism ++# exposing values to Python. ++ ++if $tracelevel then { ++ strace $tracelevel ++} ++ ++set testfile "python-template" ++set srcfile ${testfile}.cc ++set binfile ${objdir}/${subdir}/${testfile} ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable \ ++ {debug c++}] != "" } { ++ untested "Couldn't compile ${srcfile}" ++ return -1 ++} ++ ++# Start with a fresh gdb. ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++ ++gdb_test_multiple "python print 23" "verify python support" { ++ -re "not supported.*$gdb_prompt $" { ++ unsupported "python support is disabled" ++ return -1 ++ } ++ -re "$gdb_prompt $" {} ++} ++ ++proc test_template_arg {type} { ++ global testfile srcdir subdir srcfile binfile ++ if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" \ ++ executable \ ++ [list debug c++ additional_flags="-DTYPE=$type"]] != "" } { ++ untested $type ++ return -1 ++ } ++ gdb_load ${binfile} ++ if ![runto_main ] then { ++ perror "couldn't run to breakpoint" ++ return ++ } ++ # There is no executable code in main(), so we are where we want to be ++ gdb_test "print foo" "" ++ gdb_test "python foo = gdb.history(0)" "" ++ ++ # Replace '*' with '\*' in regex. ++ regsub -all {\*} $type {\*} t ++ gdb_test "python print foo.type().template_argument(0)" $t $type ++} ++ ++test_template_arg "const int" ++test_template_arg "volatile int" ++test_template_arg "const int &" ++test_template_arg "volatile int &" ++test_template_arg "volatile int * const" ++test_template_arg "volatile int * const *" ++test_template_arg "const int * volatile" ++test_template_arg "const int * volatile * const * volatile *" +diff --git a/gdb/testsuite/gdb.python/python-value.c b/gdb/testsuite/gdb.python/python-value.c +index 17e5c62..9637fe9 100644 +--- a/gdb/testsuite/gdb.python/python-value.c ++++ b/gdb/testsuite/gdb.python/python-value.c +@@ -33,13 +33,17 @@ enum e + TWO = 2 + }; + ++typedef struct s *PTR; ++ + enum e evalue = TWO; + + int + main (int argc, char *argv[]) + { ++ char *cp = argv[0]; /* Prevent gcc from optimizing argv[] out. */ + struct s s; + union u u; ++ PTR x = &s; + + s.a = 3; + s.b = 5; +diff --git a/gdb/testsuite/gdb.python/python-value.exp b/gdb/testsuite/gdb.python/python-value.exp +index 8f5e0ab..9ca9593 100644 +--- a/gdb/testsuite/gdb.python/python-value.exp ++++ b/gdb/testsuite/gdb.python/python-value.exp +@@ -227,6 +227,37 @@ proc test_value_in_inferior {} { + gdb_test "python print arg0" "0x.*$testfile\"" "verify dereferenced value" + } + ++proc test_value_after_death {} { ++ # Construct a type while the inferior is still running. ++ gdb_py_test_silent_cmd "python ptrtype = gdb.Type('PTR')" \ ++ "create PTR type" 1 ++ ++ # Check the type has the expected name. ++ gdb_test "python print ptrtype" "PTR" \ ++ "check initial PTR type" ++ ++ # Kill the inferior and remove the symbols. ++ gdb_test "kill" "" "kill the inferior" \ ++ "Kill the program being debugged. .y or n. $" \ ++ "y" ++ gdb_test "file" "" "Discard the symbols" \ ++ "Discard symbol table from.*y or n. $" \ ++ "y" ++ ++ # Now create a value using that type. Relies on arg0, created by ++ # test_value_in_inferior. ++ gdb_py_test_silent_cmd "python castval = arg0.cast(ptrtype.pointer())" \ ++ "cast arg0 to PTR" 1 ++ ++ # Make sure the type is deleted. ++ gdb_py_test_silent_cmd "python ptrtype = None" \ ++ "delete PTR type" 1 ++ ++ # Now see if the value's type is still valid. ++ gdb_test "python print castval.type()" "PTR \\*" \ ++ "print value's type" ++} ++ + + # Start with a fresh gdb. + +@@ -256,3 +287,4 @@ if ![runto_main] then { + } + + test_value_in_inferior ++test_value_after_death +diff --git a/gdb/testsuite/lib/cp-support.exp b/gdb/testsuite/lib/cp-support.exp +index dbd2f59..44e1b51 100644 +--- a/gdb/testsuite/lib/cp-support.exp ++++ b/gdb/testsuite/lib/cp-support.exp +@@ -222,7 +222,7 @@ proc cp_test_ptype_class { in_command in_testname in_key in_tag in_class_table { + + set parse_okay 0 + gdb_test_multiple "$in_command" "$in_testname // parse failed" { +- -re "type = (struct|class)${wsopt}(\[A-Za-z0-9_\]*)${wsopt}((:\[^\{\]*)?)${wsopt}\{(.*)\}${wsopt}(\[^\r\n\]*)\[\r\n\]+$gdb_prompt $" { ++ -re "type = (struct|class)${wsopt}(\[A-Za-z0-9_:\]*)${wsopt}((:\[^\{\]*)?)${wsopt}\{(.*)\}${wsopt}(\[^\r\n\]*)\[\r\n\]+$gdb_prompt $" { + set parse_okay 1 + set actual_key $expect_out(1,string) + set actual_tag $expect_out(2,string) +@@ -231,6 +231,7 @@ proc cp_test_ptype_class { in_command in_testname in_key in_tag in_class_table { + set actual_tail $expect_out(6,string) + } + } ++ + if { ! $parse_okay } then { return } + + # Check the actual key. It would be nice to require that it match +diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp +index 820ab20..8b8e7c6 100644 +--- a/gdb/testsuite/lib/gdb.exp ++++ b/gdb/testsuite/lib/gdb.exp +@@ -1162,9 +1162,12 @@ proc default_gdb_start { } { + global gdb_prompt + global timeout + global gdb_spawn_id; ++ global env + + gdb_stop_suppressing_tests; + ++ set env(LC_CTYPE) C ++ + verbose "Spawning $GDB $INTERNAL_GDBFLAGS $GDBFLAGS" + + if [info exists gdb_spawn_id] { +diff --git a/gdb/testsuite/lib/mi-support.exp b/gdb/testsuite/lib/mi-support.exp +index f62c240..bda7ea1 100644 +--- a/gdb/testsuite/lib/mi-support.exp ++++ b/gdb/testsuite/lib/mi-support.exp +@@ -1237,6 +1237,21 @@ proc mi_varobj_update_with_type_change { name new_type new_children testname } { + mi_gdb_test "-var-update $name" $er $testname + } + ++# Update a dynamic varobj named NAME. CHILDREN is a list of children, ++# in the same form as mi_list_varobj_children. TESTNAME is the name ++# of the test. ++proc mi_varobj_update_dynamic {name children testname} { ++ set children_exp_j [mi_child_regexp $children 0] ++ ++ set er "\\^done,changelist=\\\[" ++ ++ append er "{name=\"$name\",in_scope=\"true\",type_changed=\"false\"" ++ append er ",children=\\\[$children_exp_j.*\\\]}\\\]" ++ ++ verbose -log "Expecting: $er" ++ mi_gdb_test "-var-update $name" $er $testname ++} ++ + proc mi_check_varobj_value { name value testname } { + + mi_gdb_test "-var-evaluate-expression $name" \ +@@ -1244,6 +1259,42 @@ proc mi_check_varobj_value { name value testname } { + $testname + } + ++# Helper proc which constructs a child regexp for ++# mi_list_varobj_children and mi_varobj_update_dynamic. ++proc mi_child_regexp {children add_child} { ++ set children_exp {} ++ set whatever "\"\[^\"\]+\"" ++ ++ if {$add_child} { ++ set pre "child=" ++ } else { ++ set pre "" ++ } ++ ++ foreach item $children { ++ ++ set name [lindex $item 0] ++ set exp [lindex $item 1] ++ set numchild [lindex $item 2] ++ if {[llength $item] == 5} { ++ set type [lindex $item 3] ++ set value [lindex $item 4] ++ ++ lappend children_exp\ ++ "$pre{name=\"$name\",exp=\"$exp\",numchild=\"$numchild\",value=\"$value\",type=\"$type\"\(,thread-id=\"\[0-9\]+\")?}" ++ } elseif {[llength $item] == 4} { ++ set type [lindex $item 3] ++ ++ lappend children_exp\ ++ "$pre{name=\"$name\",exp=\"$exp\",numchild=\"$numchild\",type=\"$type\"\(,thread-id=\"\[0-9\]+\")?}" ++ } else { ++ lappend children_exp\ ++ "$pre{name=\"$name\",exp=\"$exp\",numchild=\"$numchild\"(,thread-id=\"\[0-9\]+\")?}" ++ } ++ } ++ return [join $children_exp ","] ++} ++ + # Check the results of the: + # + # -var-list-children VARNAME +@@ -1265,39 +1316,23 @@ proc mi_check_varobj_value { name value testname } { + # have no value. + # + proc mi_list_varobj_children { varname children testname } { ++ mi_list_varobj_children_range $varname [llength $children] $children \ ++ $testname ++} + ++# Like mi_list_varobj_children, but assumes that a subrange has been ++# selected with -var-set-child-range. NUMCHILDREN is the total number ++# of children. ++proc mi_list_varobj_children_range {varname numchildren children testname} { + set options "" + if {[llength $varname] == 2} { + set options [lindex $varname 1] + set varname [lindex $varname 0] + } + +- set numchildren [llength $children] +- set children_exp {} + set whatever "\"\[^\"\]+\"" + +- foreach item $children { +- +- set name [lindex $item 0] +- set exp [lindex $item 1] +- set numchild [lindex $item 2] +- if {[llength $item] == 5} { +- set type [lindex $item 3] +- set value [lindex $item 4] +- +- lappend children_exp\ +- "child={name=\"$name\",exp=\"$exp\",numchild=\"$numchild\",value=\"$value\",type=\"$type\"\(,thread-id=\"\[0-9\]+\")?}" +- } elseif {[llength $item] == 4} { +- set type [lindex $item 3] +- +- lappend children_exp\ +- "child={name=\"$name\",exp=\"$exp\",numchild=\"$numchild\",type=\"$type\"\(,thread-id=\"\[0-9\]+\")?}" +- } else { +- lappend children_exp\ +- "child={name=\"$name\",exp=\"$exp\",numchild=\"$numchild\"(,thread-id=\"\[0-9\]+\")?}" +- } +- } +- set children_exp_j [join $children_exp ","] ++ set children_exp_j [mi_child_regexp $children 1] + if {$numchildren} { + set expected "\\^done,numchild=\".*\",children=\\\[$children_exp_j.*\\\]" + } { +@@ -1770,3 +1805,25 @@ proc mi_check_thread_states { xstates test } { + verbose -log "expecting: $pattern" + mi_gdb_test "-thread-info" $pattern $test + } ++ ++# Return a list of MI features supported by this gdb. ++proc mi_get_features {} { ++ global expect_out mi_gdb_prompt ++ ++ send_gdb "-list-features\n" ++ ++ gdb_expect { ++ -re "\\^done,features=\\\[(.*)\\\]\r\n$mi_gdb_prompt$" { ++ regsub -all -- \" $expect_out(1,string) "" features ++ return [split $features ,] ++ } ++ -re ".*\r\n$mi_gdb_prompt$" { ++ verbose -log "got $expect_out(buffer)" ++ return "" ++ } ++ timeout { ++ verbose -log "timeout in mi_gdb_prompt" ++ return "" ++ } ++ } ++} +diff --git a/gdb/thread.c b/gdb/thread.c +index 9dea7c2..326e44e 100644 +--- a/gdb/thread.c ++++ b/gdb/thread.c +@@ -61,7 +61,6 @@ static int thread_alive (struct thread_info *); + static void info_threads_command (char *, int); + static void thread_apply_command (char *, int); + static void restore_current_thread (ptid_t); +-static void prune_threads (void); + + /* Frontend view of the thread state. Possible extensions: stepping, + finishing, until(ling),... */ +@@ -459,16 +458,23 @@ thread_alive (struct thread_info *tp) + return 1; + } + +-static void ++void + prune_threads (void) + { +- struct thread_info *tp, *next; ++ struct thread_info *tp; ++ struct thread_info **prevp = &thread_list; + +- for (tp = thread_list; tp; tp = next) ++ for (tp = *prevp; tp; tp = *prevp) + { +- next = tp->next; ++ /* If the thread has died, free it and unlink it from the list. ++ Otherwise, advance to the next thread. */ + if (!thread_alive (tp)) +- delete_thread (tp->ptid); ++ { ++ *prevp = tp->next; ++ free_thread (tp); ++ } ++ else ++ prevp = &tp->next; + } + } + +diff --git a/gdb/top.c b/gdb/top.c +index d676f02..d6b17f0 100644 +--- a/gdb/top.c ++++ b/gdb/top.c +@@ -377,6 +377,7 @@ execute_command (char *p, int from_tty) + } + + free_all_values (); ++ free_all_types (); + + /* Force cleanup of any alloca areas if using C alloca instead of + a builtin alloca. */ +@@ -1246,7 +1247,8 @@ quit_target (void *arg) + struct qt_args *qt = (struct qt_args *)arg; + + /* Kill or detach all inferiors. */ +- iterate_over_inferiors (kill_or_detach, qt); ++ if (target_has_execution) ++ iterate_over_inferiors (kill_or_detach, qt); + + /* Give all pushed targets a chance to do minimal cleanup, and pop + them all out. */ +diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c +index 83df64e..003ef3a 100644 +--- a/gdb/tracepoint.c ++++ b/gdb/tracepoint.c +@@ -1587,7 +1587,7 @@ encode_actions (struct tracepoint *t, char ***tdp_actions, + case UNOP_MEMVAL: + /* safe because we know it's a simple expression */ + tempval = evaluate_expression (exp); +- addr = VALUE_ADDRESS (tempval) + value_offset (tempval); ++ addr = value_address (tempval); + len = TYPE_LENGTH (check_typedef (exp->elts[1].type)); + add_memrange (collect, memrange_absolute, addr, len); + break; +diff --git a/gdb/typeprint.c b/gdb/typeprint.c +index 1f824fa..4a92a13 100644 +--- a/gdb/typeprint.c ++++ b/gdb/typeprint.c +@@ -35,6 +35,7 @@ + #include "gdb_string.h" + #include "exceptions.h" + #include "valprint.h" ++#include "dwarf2loc.h" + #include + + extern void _initialize_typeprint (void); +@@ -76,6 +77,9 @@ void + type_print (struct type *type, char *varstring, struct ui_file *stream, + int show) + { ++ if (show >= 0) ++ type = check_typedef (type); ++ + LA_PRINT_TYPE (type, varstring, stream, show, 0); + } + +@@ -115,7 +119,8 @@ whatis_exp (char *exp, int show) + { + struct expression *expr; + struct value *val; +- struct cleanup *old_chain = NULL; ++ /* Required at least for the object_address_set call. */ ++ struct cleanup *old_chain = make_cleanup (null_cleanup, NULL); + struct type *real_type = NULL; + struct type *type; + int full = 0; +@@ -126,12 +131,13 @@ whatis_exp (char *exp, int show) + if (exp) + { + expr = parse_expression (exp); +- old_chain = make_cleanup (free_current_contents, &expr); ++ make_cleanup (free_current_contents, &expr); + val = evaluate_type (expr); + } + else + val = access_value_history (0); + ++ object_address_set (VALUE_ADDRESS (val)); + type = value_type (val); + + get_user_print_options (&opts); +@@ -168,8 +174,7 @@ whatis_exp (char *exp, int show) + type_print (type, "", gdb_stdout, show); + printf_filtered ("\n"); + +- if (exp) +- do_cleanups (old_chain); ++ do_cleanups (old_chain); + } + + static void +@@ -236,7 +241,7 @@ print_type_scalar (struct type *type, LONGEST val, struct ui_file *stream) + break; + + case TYPE_CODE_CHAR: +- LA_PRINT_CHAR ((unsigned char) val, stream); ++ LA_PRINT_CHAR ((unsigned char) val, type, stream); + break; + + case TYPE_CODE_BOOL: +diff --git a/gdb/typeprint.h b/gdb/typeprint.h +index f561310..b39fd17 100644 +--- a/gdb/typeprint.h ++++ b/gdb/typeprint.h +@@ -26,4 +26,6 @@ void print_type_scalar (struct type * type, LONGEST, struct ui_file *); + + void c_type_print_varspec_suffix (struct type *, struct ui_file *, int, + int, int); ++ ++void c_type_print_args (struct type *, struct ui_file *, int); + #endif +diff --git a/gdb/ui-file.c b/gdb/ui-file.c +index 02a0314..5c8c96e 100644 +--- a/gdb/ui-file.c ++++ b/gdb/ui-file.c +@@ -22,6 +22,7 @@ + + #include "defs.h" + #include "ui-file.h" ++#include "gdb_obstack.h" + #include "gdb_string.h" + + #include +@@ -263,7 +264,7 @@ set_ui_file_data (struct ui_file *file, void *data, + } + + /* ui_file utility function for converting a ``struct ui_file'' into +- a memory buffer''. */ ++ a memory buffer. */ + + struct accumulated_ui_file + { +@@ -297,6 +298,23 @@ ui_file_xstrdup (struct ui_file *file, + *length = acc.length; + return acc.buffer; + } ++ ++static void ++do_ui_file_obsavestring (void *context, const char *buffer, long length) ++{ ++ struct obstack *obstack = (struct obstack *) context; ++ obstack_grow (obstack, buffer, length); ++} ++ ++char * ++ui_file_obsavestring (struct ui_file *file, struct obstack *obstack, ++ long *length) ++{ ++ ui_file_put (file, do_ui_file_obsavestring, obstack); ++ *length = obstack_object_size (obstack); ++ obstack_1grow (obstack, '\0'); ++ return obstack_finish (obstack); ++} + + /* A pure memory based ``struct ui_file'' that can be used an output + buffer. The buffers accumulated contents are available via +diff --git a/gdb/ui-file.h b/gdb/ui-file.h +index 1562d5a..d86a7eb 100644 +--- a/gdb/ui-file.h ++++ b/gdb/ui-file.h +@@ -19,6 +19,7 @@ + #ifndef UI_FILE_H + #define UI_FILE_H + ++struct obstack; + struct ui_file; + + /* Create a generic ui_file object with null methods. */ +@@ -77,7 +78,10 @@ extern void ui_file_put (struct ui_file *src, ui_file_put_method_ftype *write, v + appended NUL. */ + extern char *ui_file_xstrdup (struct ui_file *file, long *length); + +- ++/* Similar to ui_file_xstrdup, but return a new string allocated on ++ OBSTACK. */ ++extern char *ui_file_obsavestring (struct ui_file *file, ++ struct obstack *obstack, long *length); + + extern long ui_file_read (struct ui_file *file, char *buf, long length_buf); + +diff --git a/gdb/utils.c b/gdb/utils.c +index 9224839..88a9a39 100644 +--- a/gdb/utils.c ++++ b/gdb/utils.c +@@ -272,6 +272,19 @@ make_cleanup_fclose (FILE *file) + } + + static void ++do_obstack_free (void *arg) ++{ ++ struct obstack *ob = arg; ++ obstack_free (ob, NULL); ++} ++ ++struct cleanup * ++make_cleanup_obstack_free (struct obstack *obstack) ++{ ++ return make_cleanup (do_obstack_free, obstack); ++} ++ ++static void + do_ui_file_delete (void *arg) + { + ui_file_delete (arg); +@@ -1554,21 +1567,33 @@ query (const char *ctlstr, ...) + va_end (args); + } + +-/* Print an error message saying that we couldn't make sense of a +- \^mumble sequence in a string or character constant. START and END +- indicate a substring of some larger string that contains the +- erroneous backslash sequence, missing the initial backslash. */ +-static NORETURN int +-no_control_char_error (const char *start, const char *end) ++/* A helper for parse_escape that converts a host character to a ++ target character. C is the host character. If conversion is ++ possible, then the target character is stored in *TARGET_C and the ++ function returns 1. Otherwise, the function returns 0. */ ++ ++static int ++host_char_to_target (int c, int *target_c) + { +- int len = end - start; +- char *copy = alloca (end - start + 1); ++ struct obstack host_data; ++ char the_char = c; ++ struct cleanup *cleanups; ++ int result = 0; ++ ++ obstack_init (&host_data); ++ cleanups = make_cleanup_obstack_free (&host_data); ++ ++ convert_between_encodings (target_charset (), host_charset (), ++ &the_char, 1, 1, &host_data, translit_none); + +- memcpy (copy, start, len); +- copy[len] = '\0'; ++ if (obstack_object_size (&host_data) == 1) ++ { ++ result = 1; ++ *target_c = *(char *) obstack_base (&host_data); ++ } + +- error (_("There is no control character `\\%s' in the `%s' character set."), +- copy, target_charset ()); ++ do_cleanups (cleanups); ++ return result; + } + + /* Parse a C escape sequence. STRING_PTR points to a variable +@@ -1591,53 +1616,13 @@ parse_escape (char **string_ptr) + { + int target_char; + int c = *(*string_ptr)++; +- if (c_parse_backslash (c, &target_char)) +- return target_char; +- else +- switch (c) +- { ++ switch (c) ++ { + case '\n': + return -2; + case 0: + (*string_ptr)--; + return 0; +- case '^': +- { +- /* Remember where this escape sequence started, for reporting +- errors. */ +- char *sequence_start_pos = *string_ptr - 1; +- +- c = *(*string_ptr)++; +- +- if (c == '?') +- { +- /* XXXCHARSET: What is `delete' in the host character set? */ +- c = 0177; +- +- if (!host_char_to_target (c, &target_char)) +- error (_("There is no character corresponding to `Delete' " +- "in the target character set `%s'."), host_charset ()); +- +- return target_char; +- } +- else if (c == '\\') +- target_char = parse_escape (string_ptr); +- else +- { +- if (!host_char_to_target (c, &target_char)) +- no_control_char_error (sequence_start_pos, *string_ptr); +- } +- +- /* Now target_char is something like `c', and we want to find +- its control-character equivalent. */ +- if (!target_char_to_control_char (target_char, &target_char)) +- no_control_char_error (sequence_start_pos, *string_ptr); +- +- return target_char; +- } +- +- /* XXXCHARSET: we need to use isdigit and value-of-digit +- methods of the host character set here. */ + + case '0': + case '1': +@@ -1648,16 +1633,16 @@ parse_escape (char **string_ptr) + case '6': + case '7': + { +- int i = c - '0'; ++ int i = host_hex_value (c); + int count = 0; + while (++count < 3) + { + c = (**string_ptr); +- if (c >= '0' && c <= '7') ++ if (isdigit (c) && c != '8' && c != '9') + { + (*string_ptr)++; + i *= 8; +- i += c - '0'; ++ i += host_hex_value (c); + } + else + { +@@ -1666,14 +1651,39 @@ parse_escape (char **string_ptr) + } + return i; + } +- default: +- if (!host_char_to_target (c, &target_char)) +- error +- ("The escape sequence `\%c' is equivalent to plain `%c', which" +- " has no equivalent\n" "in the `%s' character set.", c, c, +- target_charset ()); +- return target_char; +- } ++ ++ case 'a': ++ c = '\a'; ++ break; ++ case 'b': ++ c = '\b'; ++ break; ++ case 'f': ++ c = '\f'; ++ break; ++ case 'n': ++ c = '\n'; ++ break; ++ case 'r': ++ c = '\r'; ++ break; ++ case 't': ++ c = '\t'; ++ break; ++ case 'v': ++ c = '\v'; ++ break; ++ ++ default: ++ break; ++ } ++ ++ if (!host_char_to_target (c, &target_char)) ++ error ++ ("The escape sequence `\%c' is equivalent to plain `%c', which" ++ " has no equivalent\n" "in the `%s' character set.", c, c, ++ target_charset ()); ++ return target_char; + } + + /* Print the character C on STREAM as part of the contents of a literal +diff --git a/gdb/v850-tdep.c b/gdb/v850-tdep.c +index 9850de4..285fe3f 100644 +--- a/gdb/v850-tdep.c ++++ b/gdb/v850-tdep.c +@@ -705,7 +705,7 @@ v850_push_dummy_call (struct gdbarch *gdbarch, + if (!v850_type_is_scalar (value_type (*args)) + && TYPE_LENGTH (value_type (*args)) > E_MAX_RETTYPE_SIZE_IN_REGS) + { +- store_unsigned_integer (valbuf, 4, VALUE_ADDRESS (*args)); ++ store_unsigned_integer (valbuf, 4, value_address (*args)); + len = 4; + val = valbuf; + } +diff --git a/gdb/valarith.c b/gdb/valarith.c +index f38cdb8..8e103cf 100644 +--- a/gdb/valarith.c ++++ b/gdb/valarith.c +@@ -164,9 +164,9 @@ an integer nor a pointer of the same type.")); + struct value * + value_subscript (struct value *array, struct value *idx) + { +- struct value *bound; + int c_style = current_language->c_style_arrays; + struct type *tarray; ++ LONGEST index = value_as_long (idx); + + array = coerce_ref (array); + tarray = check_typedef (value_type (array)); +@@ -179,13 +179,26 @@ value_subscript (struct value *array, struct value *idx) + get_discrete_bounds (range_type, &lowerbound, &upperbound); + + if (VALUE_LVAL (array) != lval_memory) +- return value_subscripted_rvalue (array, idx, lowerbound); ++ { ++ if (index >= lowerbound && index <= upperbound) ++ { ++ CORE_ADDR element_size = TYPE_LENGTH (TYPE_TARGET_TYPE (tarray)); ++ CORE_ADDR offset = (index - lowerbound) * element_size; ++ ++ return value_subscripted_rvalue (array, offset); ++ } ++ error (_("array or string index out of range")); ++ } + + if (c_style == 0) + { +- LONGEST index = value_as_long (idx); + if (index >= lowerbound && index <= upperbound) +- return value_subscripted_rvalue (array, idx, lowerbound); ++ { ++ CORE_ADDR element_size = TYPE_LENGTH (TYPE_TARGET_TYPE (tarray)); ++ CORE_ADDR offset = (index - lowerbound) * element_size; ++ ++ return value_subscripted_rvalue (array, offset); ++ } + /* Emit warning unless we have an array of unknown size. + An array of unknown size has lowerbound 0 and upperbound -1. */ + if (upperbound > -1) +@@ -194,49 +207,52 @@ value_subscript (struct value *array, struct value *idx) + c_style = 1; + } + +- if (lowerbound != 0) +- { +- bound = value_from_longest (value_type (idx), (LONGEST) lowerbound); +- idx = value_binop (idx, bound, BINOP_SUB); +- } +- ++ index -= lowerbound; + array = value_coerce_array (array); + } + + if (c_style) +- return value_ind (value_ptradd (array, idx)); ++ { ++ struct value *idx; ++ ++ idx = value_from_longest (builtin_type_int32, index); ++ return value_ind (value_ptradd (array, idx)); ++ } + else + error (_("not an array or string")); + } + +-/* Return the value of EXPR[IDX], expr an aggregate rvalue +- (eg, a vector register). This routine used to promote floats +- to doubles, but no longer does. */ ++/* Return the value of *((void *) ARRAY + ELEMENT), ARRAY an aggregate rvalue ++ (eg, a vector register). This routine used to promote floats to doubles, ++ but no longer does. OFFSET is zero-based with 0 for the lowermost existing ++ element, it must be expressed in bytes (therefore multiplied by ++ check_typedef (TYPE_TARGET_TYPE (array_type)). */ + + struct value * +-value_subscripted_rvalue (struct value *array, struct value *idx, int lowerbound) ++value_subscripted_rvalue (struct value *array, CORE_ADDR offset) + { + struct type *array_type = check_typedef (value_type (array)); + struct type *elt_type = check_typedef (TYPE_TARGET_TYPE (array_type)); +- unsigned int elt_size = TYPE_LENGTH (elt_type); +- LONGEST index = value_as_long (idx); +- unsigned int elt_offs = elt_size * longest_to_int (index - lowerbound); + struct value *v; + +- if (index < lowerbound || elt_offs >= TYPE_LENGTH (array_type)) +- error (_("no such vector element")); ++ /* Do not check TYPE_LENGTH (array_type) as we may have been given the ++ innermost dimension of a multi-dimensional Fortran array where its length ++ is shorter than the possibly accessed element offset. */ + + v = allocate_value (elt_type); + if (VALUE_LVAL (array) == lval_memory && value_lazy (array)) + set_value_lazy (v, 1); + else +- memcpy (value_contents_writeable (v), +- value_contents (array) + elt_offs, elt_size); ++ { ++ unsigned int elt_size = TYPE_LENGTH (elt_type); ++ memcpy (value_contents_writeable (v), ++ value_contents (array) + offset, elt_size); ++ } + + set_value_component_location (v, array); + VALUE_REGNUM (v) = VALUE_REGNUM (array); + VALUE_FRAME_ID (v) = VALUE_FRAME_ID (array); +- set_value_offset (v, value_offset (array) + elt_offs); ++ set_value_offset (v, value_offset (array) + offset); + return v; + } + +diff --git a/gdb/valops.c b/gdb/valops.c +index 9810f2b..14c562e 100644 +--- a/gdb/valops.c ++++ b/gdb/valops.c +@@ -38,6 +38,7 @@ + #include "cp-support.h" + #include "dfp.h" + #include "user-regs.h" ++#include "dwarf2loc.h" + + #include + #include "gdb_string.h" +@@ -254,9 +255,8 @@ value_cast_structs (struct type *type, struct value *v2) + if (v) + { + /* Downcasting is possible (t1 is superclass of v2). */ +- CORE_ADDR addr2 = VALUE_ADDRESS (v2); +- addr2 -= (VALUE_ADDRESS (v) +- + value_offset (v) ++ CORE_ADDR addr2 = value_address (v2); ++ addr2 -= (value_address (v) + + value_embedded_offset (v)); + return value_at (type, addr2); + } +@@ -371,8 +371,6 @@ value_cast (struct type *type, struct value *arg2) + new_length = val_length / element_length; + if (val_length % element_length != 0) + warning (_("array element type size does not divide object size in cast")); +- /* FIXME-type-allocation: need a way to free this type when +- we are done with it. */ + range_type = create_range_type ((struct type *) NULL, + TYPE_TARGET_TYPE (range_type), + low_bound, +@@ -511,7 +509,7 @@ value_cast (struct type *type, struct value *arg2) + } + else if (VALUE_LVAL (arg2) == lval_memory) + return value_at_lazy (type, +- VALUE_ADDRESS (arg2) + value_offset (arg2)); ++ value_address (arg2)); + else if (code1 == TYPE_CODE_VOID) + { + return value_zero (builtin_type_void, not_lval); +@@ -568,6 +566,64 @@ value_one (struct type *type, enum lval_type lv) + return val; + } + ++/* object_address_set must be already called before this function. */ ++ ++const char * ++object_address_data_not_valid (struct type *type) ++{ ++ /* Attributes are present only at the target type of a typedef. Make the ++ call conditional as it would otherwise loop through type_length_get. */ ++ if (TYPE_CODE (type) == TYPE_CODE_TYPEDEF) ++ CHECK_TYPEDEF (type); ++ ++ /* DW_AT_associated has a preference over DW_AT_allocated. */ ++ if (TYPE_NOT_ASSOCIATED (type) ++ || (TYPE_ASSOCIATED (type) != NULL ++ && 0 == dwarf_locexpr_baton_eval (TYPE_ASSOCIATED (type)))) ++ return N_("object is not associated"); ++ ++ if (TYPE_NOT_ALLOCATED (type) ++ || (TYPE_ALLOCATED (type) != NULL ++ && 0 == dwarf_locexpr_baton_eval (TYPE_ALLOCATED (type)))) ++ return N_("object is not allocated"); ++ ++ return NULL; ++} ++ ++/* Return non-zero if the variable is valid. If it is valid the function ++ may store the data address (DW_AT_DATA_LOCATION) of TYPE at *ADDRESS_RETURN. ++ You must set *ADDRESS_RETURN as VALUE_ADDRESS (VAL) before calling this ++ function. If no DW_AT_DATA_LOCATION is present for TYPE the address at ++ *ADDRESS_RETURN is left unchanged. ADDRESS_RETURN must not be NULL, use ++ object_address_data_not_valid () for just the data validity check. */ ++ ++int ++object_address_get_data (struct type *type, CORE_ADDR *address_return) ++{ ++ gdb_assert (address_return != NULL); ++ ++ object_address_set (*address_return); ++ ++ /* TYPE_DATA_LOCATION_DWARF_BLOCK / TYPE_DATA_LOCATION_ADDR are present only ++ at the target type of a typedef. */ ++ CHECK_TYPEDEF (type); ++ ++ if (object_address_data_not_valid (type) != NULL) ++ { ++ /* Do not try to evaluate DW_AT_data_location as it may even crash ++ (it would just return the value zero in the gfortran case). */ ++ return 0; ++ } ++ ++ if (TYPE_DATA_LOCATION_IS_ADDR (type)) ++ *address_return = TYPE_DATA_LOCATION_ADDR (type); ++ else if (TYPE_DATA_LOCATION_DWARF_BLOCK (type) != NULL) ++ *address_return ++ = dwarf_locexpr_baton_eval (TYPE_DATA_LOCATION_DWARF_BLOCK (type)); ++ ++ return 1; ++} ++ + /* Return a value with type TYPE located at ADDR. + + Call value_at only if the data needs to be fetched immediately; +@@ -593,7 +649,7 @@ value_at (struct type *type, CORE_ADDR addr) + read_memory (addr, value_contents_all_raw (val), TYPE_LENGTH (type)); + + VALUE_LVAL (val) = lval_memory; +- VALUE_ADDRESS (val) = addr; ++ set_value_address (val, addr); + + return val; + } +@@ -611,7 +667,7 @@ value_at_lazy (struct type *type, CORE_ADDR addr) + val = allocate_value_lazy (type); + + VALUE_LVAL (val) = lval_memory; +- VALUE_ADDRESS (val) = addr; ++ set_value_address (val, addr); + + return val; + } +@@ -637,11 +693,19 @@ value_fetch_lazy (struct value *val) + allocate_value_contents (val); + if (VALUE_LVAL (val) == lval_memory) + { +- CORE_ADDR addr = VALUE_ADDRESS (val) + value_offset (val); +- int length = TYPE_LENGTH (check_typedef (value_enclosing_type (val))); ++ CORE_ADDR addr = VALUE_ADDRESS (val); ++ ++ if (object_address_get_data (value_type (val), &addr)) ++ { ++ struct type *type = value_enclosing_type (val); ++ int length = TYPE_LENGTH (check_typedef (type)); + +- if (length) +- read_memory (addr, value_contents_all_raw (val), length); ++ if (length) ++ { ++ addr += value_offset (val); ++ read_memory (addr, value_contents_all_raw (val), length); ++ } ++ } + } + else if (VALUE_LVAL (val) == lval_register) + { +@@ -709,7 +773,7 @@ value_fetch_lazy (struct value *val) + VALUE_REGNUM (new_val)); + else if (VALUE_LVAL (new_val) == lval_memory) + fprintf_unfiltered (gdb_stdlog, " address=0x%s", +- paddr_nz (VALUE_ADDRESS (new_val))); ++ paddr_nz (value_address (new_val))); + else + fprintf_unfiltered (gdb_stdlog, " computed"); + +@@ -813,16 +877,15 @@ value_assign (struct value *toval, struct value *fromval) + error (_("Can't handle bitfields which don't fit in a %d bit word."), + (int) sizeof (LONGEST) * HOST_CHAR_BIT); + +- read_memory (VALUE_ADDRESS (toval) + value_offset (toval), +- buffer, changed_len); ++ read_memory (value_address (toval), buffer, changed_len); + modify_field (buffer, value_as_long (fromval), + value_bitpos (toval), value_bitsize (toval)); +- changed_addr = VALUE_ADDRESS (toval) + value_offset (toval); ++ changed_addr = value_address (toval); + dest_buffer = buffer; + } + else + { +- changed_addr = VALUE_ADDRESS (toval) + value_offset (toval); ++ changed_addr = value_address (toval); + changed_len = TYPE_LENGTH (type); + dest_buffer = value_contents (fromval); + } +@@ -985,11 +1048,11 @@ value_repeat (struct value *arg1, int count) + + val = allocate_repeat_value (value_enclosing_type (arg1), count); + +- read_memory (VALUE_ADDRESS (arg1) + value_offset (arg1), ++ read_memory (value_address (arg1), + value_contents_all_raw (val), + TYPE_LENGTH (value_enclosing_type (val))); + VALUE_LVAL (val) = lval_memory; +- VALUE_ADDRESS (val) = VALUE_ADDRESS (arg1) + value_offset (arg1); ++ set_value_address (val, value_address (arg1)); + + return val; + } +@@ -1036,10 +1099,11 @@ address_of_variable (struct symbol *var, struct block *b) + + val = value_of_variable (var, b); + +- if ((VALUE_LVAL (val) == lval_memory && value_lazy (val)) ++ if ((VALUE_LVAL (val) == lval_memory && value_lazy (val) ++ && object_address_get_data (type, &VALUE_ADDRESS (val))) + || TYPE_CODE (type) == TYPE_CODE_FUNC) + { +- CORE_ADDR addr = VALUE_ADDRESS (val); ++ CORE_ADDR addr = value_address (val); + return value_from_pointer (lookup_pointer_type (type), addr); + } + +@@ -1145,6 +1209,7 @@ struct value * + value_coerce_array (struct value *arg1) + { + struct type *type = check_typedef (value_type (arg1)); ++ CORE_ADDR address; + + /* If the user tries to do something requiring a pointer with an + array that has not yet been pushed to the target, then this would +@@ -1154,8 +1219,12 @@ value_coerce_array (struct value *arg1) + if (VALUE_LVAL (arg1) != lval_memory) + error (_("Attempt to take address of value not located in memory.")); + ++ address = VALUE_ADDRESS (arg1); ++ if (!object_address_get_data (type, &address)) ++ error (_("Attempt to take address of non-valid value.")); ++ + return value_from_pointer (lookup_pointer_type (TYPE_TARGET_TYPE (type)), +- (VALUE_ADDRESS (arg1) + value_offset (arg1))); ++ address + value_offset (arg1)); + } + + /* Given a value which is a function, return a value which is a pointer +@@ -1170,7 +1239,7 @@ value_coerce_function (struct value *arg1) + error (_("Attempt to take address of value not located in memory.")); + + retval = value_from_pointer (lookup_pointer_type (value_type (arg1)), +- (VALUE_ADDRESS (arg1) + value_offset (arg1))); ++ (value_address (arg1))); + return retval; + } + +@@ -1205,8 +1274,7 @@ value_addr (struct value *arg1) + + /* Get target memory address */ + arg2 = value_from_pointer (lookup_pointer_type (value_type (arg1)), +- (VALUE_ADDRESS (arg1) +- + value_offset (arg1) ++ (value_address (arg1) + + value_embedded_offset (arg1))); + + /* This may be a pointer to a base subobject; so remember the +@@ -1352,6 +1420,24 @@ value_array (int lowbound, int highbound, struct value **elemvec) + return val; + } + ++struct value * ++value_typed_string (char *ptr, int len, struct type *char_type) ++{ ++ struct value *val; ++ int lowbound = current_language->string_lower_bound; ++ int highbound = len / TYPE_LENGTH (char_type); ++ struct type *rangetype = create_range_type ((struct type *) NULL, ++ builtin_type_int32, ++ lowbound, ++ highbound + lowbound - 1); ++ struct type *stringtype ++ = create_array_type ((struct type *) NULL, char_type, rangetype); ++ ++ val = allocate_value (stringtype); ++ memcpy (value_contents_raw (val), ptr, len); ++ return val; ++} ++ + /* Create a value for a string constant by allocating space in the + inferior, copying the data into that space, and returning the + address with type TYPE_CODE_STRING. PTR points to the string +@@ -1600,8 +1686,7 @@ search_struct_field (char *name, struct value *arg1, int offset, + + boffset = baseclass_offset (type, i, + value_contents (arg1) + offset, +- VALUE_ADDRESS (arg1) +- + value_offset (arg1) + offset); ++ value_address (arg1) + offset); + if (boffset == -1) + error (_("virtual baseclass botch")); + +@@ -1616,13 +1701,13 @@ search_struct_field (char *name, struct value *arg1, int offset, + + v2 = allocate_value (basetype); + base_addr = +- VALUE_ADDRESS (arg1) + value_offset (arg1) + boffset; ++ value_address (arg1) + boffset; + if (target_read_memory (base_addr, + value_contents_raw (v2), + TYPE_LENGTH (basetype)) != 0) + error (_("virtual baseclass botch")); + VALUE_LVAL (v2) = lval_memory; +- VALUE_ADDRESS (v2) = base_addr; ++ set_value_address (v2, base_addr); + } + else + { +@@ -1745,8 +1830,7 @@ search_struct_method (char *name, struct value **arg1p, + if (offset < 0 || offset >= TYPE_LENGTH (type)) + { + gdb_byte *tmp = alloca (TYPE_LENGTH (baseclass)); +- if (target_read_memory (VALUE_ADDRESS (*arg1p) +- + value_offset (*arg1p) + offset, ++ if (target_read_memory (value_address (*arg1p) + offset, + tmp, TYPE_LENGTH (baseclass)) != 0) + error (_("virtual baseclass botch")); + base_valaddr = tmp; +@@ -1755,8 +1839,7 @@ search_struct_method (char *name, struct value **arg1p, + base_valaddr = value_contents (*arg1p) + offset; + + base_offset = baseclass_offset (type, i, base_valaddr, +- VALUE_ADDRESS (*arg1p) +- + value_offset (*arg1p) + offset); ++ value_address (*arg1p) + offset); + if (base_offset == -1) + error (_("virtual baseclass botch")); + } +@@ -1965,7 +2048,7 @@ find_method_list (struct value **argp, char *method, + base_offset = value_offset (*argp) + offset; + base_offset = baseclass_offset (type, i, + value_contents (*argp) + base_offset, +- VALUE_ADDRESS (*argp) + base_offset); ++ value_address (*argp) + base_offset); + if (base_offset == -1) + error (_("virtual baseclass botch")); + } +@@ -2083,12 +2166,25 @@ find_overload_match (struct type **arg_types, int nargs, + if (method) + { + gdb_assert (obj); ++ ++ /* OBJ may be a pointer value rather than the object itself. */ ++ obj = coerce_ref (obj); ++ while (TYPE_CODE (check_typedef (value_type (obj))) == TYPE_CODE_PTR) ++ obj = coerce_ref (value_ind (obj)); + obj_type_name = TYPE_NAME (value_type (obj)); +- /* Hack: evaluate_subexp_standard often passes in a pointer +- value rather than the object itself, so try again. */ +- if ((!obj_type_name || !*obj_type_name) +- && (TYPE_CODE (value_type (obj)) == TYPE_CODE_PTR)) +- obj_type_name = TYPE_NAME (TYPE_TARGET_TYPE (value_type (obj))); ++ ++ /* First check whether this is a data member, e.g. a pointer to ++ a function. */ ++ if (TYPE_CODE (check_typedef (value_type (obj))) == TYPE_CODE_STRUCT) ++ { ++ *valp = search_struct_field (name, obj, 0, ++ check_typedef (value_type (obj)), 0); ++ if (*valp) ++ { ++ *staticp = 1; ++ return 0; ++ } ++ } + + fns_ptr = value_find_oload_method_list (&temp, name, + 0, &num_fns, +@@ -2108,16 +2204,29 @@ find_overload_match (struct type **arg_types, int nargs, + } + else + { +- const char *qualified_name = SYMBOL_CPLUS_DEMANGLED_NAME (fsym); ++ const char *qualified_name = SYMBOL_NATURAL_NAME (fsym); + +- /* If we have a C++ name, try to extract just the function +- part. */ +- if (qualified_name) +- func_name = cp_func_name (qualified_name); ++ /* If we have a function with a C++ name, try to extract just ++ the function part. Do not try this for non-functions (e.g. ++ function pointers). */ ++ if (qualified_name ++ && TYPE_CODE (check_typedef (SYMBOL_TYPE (fsym))) == TYPE_CODE_FUNC) ++ { ++ func_name = cp_func_name (qualified_name); ++ ++ /* If cp_func_name did not remove anything, the name of the ++ symbol did not include scope or argument types - it was ++ probably a C-style function. */ ++ if (func_name && strcmp (func_name, qualified_name) == 0) ++ { ++ xfree (func_name); ++ func_name = NULL; ++ } ++ } + +- /* If there was no C++ name, this must be a C-style function. +- Just return the same symbol. Do the same if cp_func_name +- fails for some reason. */ ++ /* If there was no C++ name, this must be a C-style function or ++ not a function at all. Just return the same symbol. Do the ++ same if cp_func_name fails for some reason. */ + if (func_name == NULL) + { + *symp = fsym; +@@ -2558,8 +2667,8 @@ check_field (struct type *type, const char *name) + the comment before value_struct_elt_for_reference. */ + + struct value * +-value_aggregate_elt (struct type *curtype, +- char *name, int want_address, ++value_aggregate_elt (struct type *curtype, char *name, ++ struct type *expect_type, int want_address, + enum noside noside) + { + switch (TYPE_CODE (curtype)) +@@ -2567,7 +2676,7 @@ value_aggregate_elt (struct type *curtype, + case TYPE_CODE_STRUCT: + case TYPE_CODE_UNION: + return value_struct_elt_for_reference (curtype, 0, curtype, +- name, NULL, ++ name, expect_type, + want_address, noside); + case TYPE_CODE_NAMESPACE: + return value_namespace_elt (curtype, name, +@@ -2671,7 +2780,7 @@ value_struct_elt_for_reference (struct type *domain, int offset, + if (intype) + { + while (j--) +- if (TYPE_FN_FIELD_TYPE (f, j) == intype) ++ if (compare_parameters (TYPE_FN_FIELD_TYPE (f, j), intype)) + break; + if (j < 0) + error (_("no member function matches that type instantiation")); +@@ -2725,7 +2834,7 @@ value_struct_elt_for_reference (struct type *domain, int offset, + result = allocate_value (lookup_methodptr_type (TYPE_FN_FIELD_TYPE (f, j))); + cplus_make_method_ptr (value_type (result), + value_contents_writeable (result), +- VALUE_ADDRESS (v), 0); ++ value_address (v), 0); + } + } + return result; +@@ -2791,7 +2900,7 @@ value_maybe_namespace_elt (const struct type *curtype, + struct symbol *sym; + struct value *result; + +- sym = cp_lookup_symbol_namespace (namespace_name, name, NULL, ++ sym = cp_lookup_symbol_namespace_incremental (namespace_name, name, NULL, + get_selected_block (0), + VAR_DOMAIN); + +@@ -2884,7 +2993,7 @@ value_full_object (struct value *argp, + /* Go back by the computed top_offset from the beginning of the + object, adjusting for the embedded offset of argp if that's what + value_rtti_type used for its computation. */ +- new_val = value_at_lazy (real_type, VALUE_ADDRESS (argp) - top + ++ new_val = value_at_lazy (real_type, value_address (argp) - top + + (using_enc ? 0 : value_embedded_offset (argp))); + deprecated_set_value_type (new_val, value_type (argp)); + set_value_embedded_offset (new_val, (using_enc +@@ -2989,8 +3098,6 @@ value_slice (struct value *array, int lowbound, int length) + || lowbound + length - 1 > upperbound) + error (_("slice out of range")); + +- /* FIXME-type-allocation: need a way to free this type when we are +- done with it. */ + slice_range_type = create_range_type ((struct type *) NULL, + TYPE_TARGET_TYPE (range_type), + lowbound, +diff --git a/gdb/valprint.c b/gdb/valprint.c +index b02e9df..a9e8227 100644 +--- a/gdb/valprint.c ++++ b/gdb/valprint.c +@@ -34,6 +34,7 @@ + #include "doublest.h" + #include "exceptions.h" + #include "dfp.h" ++#include "python/python.h" + + #include + +@@ -80,7 +81,9 @@ struct value_print_options user_print_options = + 0, /* print_array_indexes */ + 0, /* deref_ref */ + 1, /* static_field_print */ +- 1 /* pascal_static_field_print */ ++ 1, /* pascal_static_field_print */ ++ 0, /* raw */ ++ 0 /* summary */ + }; + + /* Initialize *OPTS to be a copy of the user print options. */ +@@ -257,6 +260,15 @@ val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, + return (0); + } + ++ if (!options->raw) ++ { ++ ret = apply_val_pretty_printer (type, valaddr, embedded_offset, ++ address, stream, recurse, options, ++ language); ++ if (ret) ++ return ret; ++ } ++ + TRY_CATCH (except, RETURN_MASK_ERROR) + { + ret = language->la_val_print (type, valaddr, embedded_offset, address, +@@ -287,6 +299,13 @@ value_check_printable (struct value *val, struct ui_file *stream) + return 0; + } + ++ if (TYPE_CODE (value_type (val)) == TYPE_CODE_INTERNAL_FUNCTION) ++ { ++ fprintf_filtered (stream, _(""), ++ value_internal_function_name (val)); ++ return 0; ++ } ++ + return 1; + } + +@@ -308,7 +327,7 @@ common_val_print (struct value *val, struct ui_file *stream, int recurse, + return 0; + + return val_print (value_type (val), value_contents_all (val), +- value_embedded_offset (val), VALUE_ADDRESS (val), ++ value_embedded_offset (val), value_address (val), + stream, recurse, options, language); + } + +@@ -324,6 +343,18 @@ value_print (struct value *val, struct ui_file *stream, + if (!value_check_printable (val, stream)) + return 0; + ++ if (!options->raw) ++ { ++ int r = apply_val_pretty_printer (value_type (val), ++ value_contents_all (val), ++ value_embedded_offset (val), ++ value_address (val), ++ stream, 0, options, ++ current_language); ++ if (r) ++ return r; ++ } ++ + return LA_VALUE_PRINT (val, stream, options); + } + +@@ -919,7 +950,8 @@ print_hex_chars (struct ui_file *stream, const gdb_byte *valaddr, + Omit any leading zero chars. */ + + void +-print_char_chars (struct ui_file *stream, const gdb_byte *valaddr, ++print_char_chars (struct ui_file *stream, struct type *type, ++ const gdb_byte *valaddr, + unsigned len, enum bfd_endian byte_order) + { + const gdb_byte *p; +@@ -932,7 +964,7 @@ print_char_chars (struct ui_file *stream, const gdb_byte *valaddr, + + while (p < valaddr + len) + { +- LA_EMIT_CHAR (*p, stream, '\''); ++ LA_EMIT_CHAR (*p, type, stream, '\''); + ++p; + } + } +@@ -944,7 +976,7 @@ print_char_chars (struct ui_file *stream, const gdb_byte *valaddr, + + while (p >= valaddr) + { +- LA_EMIT_CHAR (*p, stream, '\''); ++ LA_EMIT_CHAR (*p, type, stream, '\''); + --p; + } + } +@@ -1085,6 +1117,7 @@ val_print_array_elements (struct type *type, const gdb_byte *valaddr, + + for (; i < len && things_printed < options->print_max; i++) + { ++ size_t elt_offset = i * eltlen; + if (i != 0) + { + if (options->prettyprint_arrays) +@@ -1104,7 +1137,7 @@ val_print_array_elements (struct type *type, const gdb_byte *valaddr, + rep1 = i + 1; + reps = 1; + while ((rep1 < len) && +- !memcmp (valaddr + i * eltlen, valaddr + rep1 * eltlen, eltlen)) ++ !memcmp (valaddr + elt_offset, valaddr + rep1 * eltlen, eltlen)) + { + ++reps; + ++rep1; +@@ -1112,7 +1145,7 @@ val_print_array_elements (struct type *type, const gdb_byte *valaddr, + + if (reps > options->repeat_count_threshold) + { +- val_print (elttype, valaddr + i * eltlen, 0, address + i * eltlen, ++ val_print (elttype, valaddr + elt_offset, 0, address + elt_offset, + stream, recurse + 1, options, current_language); + annotate_elt_rep (reps); + fprintf_filtered (stream, " ", reps); +@@ -1123,7 +1156,7 @@ val_print_array_elements (struct type *type, const gdb_byte *valaddr, + } + else + { +- val_print (elttype, valaddr + i * eltlen, 0, address + i * eltlen, ++ val_print (elttype, valaddr + elt_offset, 0, address + elt_offset, + stream, recurse + 1, options, current_language); + annotate_elt (); + things_printed++; +@@ -1315,7 +1348,8 @@ read_string (CORE_ADDR addr, int len, int width, unsigned int fetchlimit, + whichever is smaller. */ + + int +-val_print_string (CORE_ADDR addr, int len, int width, struct ui_file *stream, ++val_print_string (struct type *elttype, CORE_ADDR addr, int len, ++ struct ui_file *stream, + const struct value_print_options *options) + { + int force_ellipsis = 0; /* Force ellipsis to be printed if nonzero. */ +@@ -1325,6 +1359,7 @@ val_print_string (CORE_ADDR addr, int len, int width, struct ui_file *stream, + int bytes_read; + gdb_byte *buffer = NULL; /* Dynamically growable fetch buffer. */ + struct cleanup *old_chain = NULL; /* Top of the old cleanup chain. */ ++ int width = TYPE_LENGTH (elttype); + + /* First we need to figure out the limit on the number of characters we are + going to attempt to fetch and print. This is actually pretty simple. If +@@ -1378,7 +1413,7 @@ val_print_string (CORE_ADDR addr, int len, int width, struct ui_file *stream, + { + fputs_filtered (" ", stream); + } +- LA_PRINT_STRING (stream, buffer, bytes_read / width, width, force_ellipsis, options); ++ LA_PRINT_STRING (stream, elttype, buffer, bytes_read / width, force_ellipsis, options); + } + + if (errcode != 0) +diff --git a/gdb/valprint.h b/gdb/valprint.h +index 8b65af6..4f63fa6 100644 +--- a/gdb/valprint.h ++++ b/gdb/valprint.h +@@ -84,6 +84,12 @@ struct value_print_options + /* If nonzero, print static fields for Pascal. FIXME: C++ and Java + share one flag, why not Pascal too? */ + int pascal_static_field_print; ++ ++ /* Controls Python pretty-printing. */ ++ int raw; ++ ++ /* If nonzero, print the value in "summary" form. */ ++ int summary; + }; + + /* The global print options set by the user. In general this should +@@ -134,9 +140,10 @@ extern void print_decimal_chars (struct ui_file *, const gdb_byte *, + extern void print_hex_chars (struct ui_file *, const gdb_byte *, + unsigned int, enum bfd_endian); + +-extern void print_char_chars (struct ui_file *, const gdb_byte *, +- unsigned int, enum bfd_endian); ++extern void print_char_chars (struct ui_file *, struct type *, ++ const gdb_byte *, unsigned int, enum bfd_endian); + + int read_string (CORE_ADDR addr, int len, int width, unsigned int fetchlimit, + gdb_byte **buffer, int *bytes_read); ++ + #endif +diff --git a/gdb/value.c b/gdb/value.c +index 4d4329e..5c81d83 100644 +--- a/gdb/value.c ++++ b/gdb/value.c +@@ -36,6 +36,7 @@ + #include "block.h" + #include "dfp.h" + #include "objfiles.h" ++#include "cli/cli-decode.h" + #include "valprint.h" + + #include "python/python.h" +@@ -44,6 +45,23 @@ + + void _initialize_values (void); + ++/* Definition of a user function. */ ++struct internal_function ++{ ++ /* The name of the function. It is a bit odd to have this in the ++ function itself -- the user might use a differently-named ++ convenience variable to hold the function. */ ++ char *name; ++ ++ /* The handler. */ ++ internal_function_fn handler; ++ ++ /* User data for the handler. */ ++ void *cookie; ++}; ++ ++static struct cmd_list_element *functionlist; ++ + struct value + { + /* Type of value; either not an lval, or one of the various +@@ -203,6 +221,10 @@ struct value_history_chunk + static struct value_history_chunk *value_history_chain; + + static int value_history_count; /* Abs number of last entry stored */ ++ ++/* The type of internal functions. */ ++ ++static struct type *internal_fn_type; + + /* List of all value objects currently allocated + (except for those released by calls to release_value) +@@ -225,9 +247,11 @@ allocate_value_lazy (struct type *type) + val->next = all_values; + all_values = val; + val->type = type; ++ type_incref (type); + val->enclosing_type = type; ++ type_incref (type); + VALUE_LVAL (val) = not_lval; +- VALUE_ADDRESS (val) = 0; ++ val->location.address = 0; + VALUE_FRAME_ID (val) = null_frame_id; + val->offset = 0; + val->bitpos = 0; +@@ -269,13 +293,9 @@ struct value * + allocate_repeat_value (struct type *type, int count) + { + int low_bound = current_language->string_lower_bound; /* ??? */ +- /* FIXME-type-allocation: need a way to free this type when we are +- done with it. */ + struct type *range_type + = create_range_type ((struct type *) NULL, builtin_type_int32, + low_bound, count + low_bound - 1); +- /* FIXME-type-allocation: need a way to free this type when we are +- done with it. */ + return allocate_value (create_array_type ((struct type *) NULL, + type, range_type)); + } +@@ -335,6 +355,8 @@ value_type (struct value *value) + void + deprecated_set_value_type (struct value *value, struct type *type) + { ++ type_incref (type); ++ type_decref (value->type); + value->type = type; + } + +@@ -509,6 +531,32 @@ deprecated_value_address_hack (struct value *value) + return &value->location.address; + } + ++CORE_ADDR ++value_address (struct value *value) ++{ ++ if (value->lval == lval_internalvar ++ || value->lval == lval_internalvar_component) ++ return 0; ++ return value->location.address + value->offset; ++} ++ ++CORE_ADDR ++value_raw_address (struct value *value) ++{ ++ if (value->lval == lval_internalvar ++ || value->lval == lval_internalvar_component) ++ return 0; ++ return value->location.address; ++} ++ ++void ++set_value_address (struct value *value, CORE_ADDR addr) ++{ ++ gdb_assert (value->lval != lval_internalvar ++ && value->lval != lval_internalvar_component); ++ value->location.address = addr; ++} ++ + struct internalvar ** + deprecated_value_internalvar_hack (struct value *value) + { +@@ -547,11 +595,16 @@ value_mark (void) + return all_values; + } + ++/* Deallocate a value and run destructors if needed. */ ++ + void + value_free (struct value *val) + { + if (val) + { ++ type_decref (val->type); ++ type_decref (val->enclosing_type); ++ + if (VALUE_LVAL (val) == lval_computed) + { + struct lval_funcs *funcs = val->location.computed.funcs; +@@ -655,6 +708,8 @@ value_copy (struct value *arg) + val = allocate_value_lazy (encl_type); + else + val = allocate_value (encl_type); ++ type_incref (arg->type); ++ type_decref (val->type); + val->type = arg->type; + VALUE_LVAL (val) = VALUE_LVAL (arg); + val->location = arg->location; +@@ -693,6 +748,7 @@ set_value_component_location (struct value *component, struct value *whole) + VALUE_LVAL (component) = VALUE_LVAL (whole); + + component->location = whole->location; ++ + if (VALUE_LVAL (whole) == lval_computed) + { + struct lval_funcs *funcs = whole->location.computed.funcs; +@@ -700,6 +756,8 @@ set_value_component_location (struct value *component, struct value *whole) + if (funcs->copy_closure) + component->location.computed.closure = funcs->copy_closure (whole); + } ++ ++ object_address_get_data (value_type (whole), &VALUE_ADDRESS (component)); + } + + +@@ -830,6 +888,25 @@ show_values (char *num_exp, int from_tty) + num_exp[1] = '\0'; + } + } ++ ++/* Sanity check for memory leaks and proper types reference counting. */ ++ ++static void ++value_history_cleanup (void *unused) ++{ ++ while (value_history_chain) ++ { ++ struct value_history_chunk *chunk = value_history_chain; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE (chunk->values); i++) ++ value_free (chunk->values[i]); ++ ++ value_history_chain = chunk->next; ++ xfree (chunk); ++ } ++ value_history_count = 0; ++} + + /* Internal variables. These are variables within the debugger + that hold values assigned by debugger commands. +@@ -878,7 +955,7 @@ init_if_undefined_command (char* args, int from_tty) + the return value is NULL. */ + + struct internalvar * +-lookup_only_internalvar (char *name) ++lookup_only_internalvar (const char *name) + { + struct internalvar *var; + +@@ -894,7 +971,7 @@ lookup_only_internalvar (char *name) + NAME should not normally include a dollar sign. */ + + struct internalvar * +-create_internalvar (char *name) ++create_internalvar (const char *name) + { + struct internalvar *var; + var = (struct internalvar *) xmalloc (sizeof (struct internalvar)); +@@ -902,6 +979,7 @@ create_internalvar (char *name) + var->value = allocate_value (builtin_type_void); + var->endian = gdbarch_byte_order (current_gdbarch); + var->make_value = NULL; ++ var->canonical = 0; + release_value (var->value); + var->next = internalvars; + internalvars = var; +@@ -934,7 +1012,7 @@ create_internalvar_type_lazy (char *name, internalvar_make_value fun) + one is created, with a void value. */ + + struct internalvar * +-lookup_internalvar (char *name) ++lookup_internalvar (const char *name) + { + struct internalvar *var; + +@@ -1031,6 +1109,9 @@ set_internalvar (struct internalvar *var, struct value *val) + { + struct value *newval; + ++ if (var->canonical) ++ error (_("Cannot overwrite convenience function %s"), var->name); ++ + newval = value_copy (val); + newval->modifiable = 1; + +@@ -1042,7 +1123,7 @@ set_internalvar (struct internalvar *var, struct value *val) + + /* Begin code which must not call error(). If var->value points to + something free'd, an error() obviously leaves a dangling pointer. +- But we also get a danling pointer if var->value points to ++ But we also get a dangling pointer if var->value points to + something in the value chain (i.e., before release_value is + called), because after the error free_all_values will get called before + long. */ +@@ -1059,6 +1140,76 @@ internalvar_name (struct internalvar *var) + return var->name; + } + ++static struct value * ++value_create_internal_function (const char *name, ++ internal_function_fn handler, ++ void *cookie) ++{ ++ struct value *result = allocate_value (internal_fn_type); ++ gdb_byte *addr = value_contents_writeable (result); ++ struct internal_function **fnp = (struct internal_function **) addr; ++ struct internal_function *ifn = XNEW (struct internal_function); ++ ifn->name = xstrdup (name); ++ ifn->handler = handler; ++ ifn->cookie = cookie; ++ *fnp = ifn; ++ return result; ++} ++ ++char * ++value_internal_function_name (struct value *val) ++{ ++ gdb_byte *addr = value_contents_writeable (val); ++ struct internal_function *ifn = * (struct internal_function **) addr; ++ return ifn->name; ++} ++ ++struct value * ++call_internal_function (struct value *func, int argc, struct value **argv) ++{ ++ gdb_byte *addr = value_contents_writeable (func); ++ struct internal_function *ifn = * (struct internal_function **) addr; ++ return (*ifn->handler) (ifn->cookie, argc, argv); ++} ++ ++/* The 'function' command. This does nothing -- it is just a ++ placeholder to let "help function NAME" work. This is also used as ++ the implementation of the sub-command that is created when ++ registering an internal function. */ ++static void ++function_command (char *command, int from_tty) ++{ ++ /* Do nothing. */ ++} ++ ++/* Clean up if an internal function's command is destroyed. */ ++static void ++function_destroyer (struct cmd_list_element *self, void *ignore) ++{ ++ xfree (self->name); ++ xfree (self->doc); ++} ++ ++/* Add a new internal function. NAME is the name of the function; DOC ++ is a documentation string describing the function. HANDLER is ++ called when the function is invoked. COOKIE is an arbitrary ++ pointer which is passed to HANDLER and is intended for "user ++ data". */ ++void ++add_internal_function (const char *name, const char *doc, ++ internal_function_fn handler, void *cookie) ++{ ++ struct cmd_list_element *cmd; ++ struct internalvar *var = lookup_internalvar (name); ++ struct value *fnval = value_create_internal_function (name, handler, cookie); ++ set_internalvar (var, fnval); ++ var->canonical = 1; ++ ++ cmd = add_cmd (xstrdup (name), no_class, function_command, (char *) doc, ++ &functionlist); ++ cmd->destroyer = function_destroyer; ++} ++ + /* Update VALUE before discarding OBJFILE. COPIED_TYPES is used to + prevent cycles / duplicates. */ + +@@ -1067,12 +1218,21 @@ preserve_one_value (struct value *value, struct objfile *objfile, + htab_t copied_types) + { + if (TYPE_OBJFILE (value->type) == objfile) +- value->type = copy_type_recursive (objfile, value->type, copied_types); ++ { ++ /* No need to decref the old type here, since we know it has no ++ reference count. */ ++ value->type = copy_type_recursive (value->type, copied_types); ++ type_incref (value->type); ++ } + + if (TYPE_OBJFILE (value->enclosing_type) == objfile) +- value->enclosing_type = copy_type_recursive (objfile, +- value->enclosing_type, +- copied_types); ++ { ++ /* No need to decref the old type here, since we know it has no ++ reference count. */ ++ value->enclosing_type = copy_type_recursive (value->enclosing_type, ++ copied_types); ++ type_incref (value->enclosing_type); ++ } + } + + /* Update the internal variables and value history when OBJFILE is +@@ -1196,7 +1356,7 @@ value_as_address (struct value *val) + + Upon entry to this function, if VAL is a value of type `function' + (that is, TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_FUNC), then +- VALUE_ADDRESS (val) is the address of the function. This is what ++ value_address (val) is the address of the function. This is what + you'll get if you evaluate an expression like `main'. The call + to COERCE_ARRAY below actually does all the usual unary + conversions, which includes converting values of type `function' +@@ -1216,7 +1376,7 @@ value_as_address (struct value *val) + function, just return its address directly. */ + if (TYPE_CODE (value_type (val)) == TYPE_CODE_FUNC + || TYPE_CODE (value_type (val)) == TYPE_CODE_METHOD) +- return VALUE_ADDRESS (val); ++ return value_address (val); + + val = coerce_array (val); + +@@ -1447,7 +1607,7 @@ value_static_field (struct type *type, int fieldno) + } + if (retval && VALUE_LVAL (retval) == lval_memory) + SET_FIELD_PHYSADDR (TYPE_FIELD (type, fieldno), +- VALUE_ADDRESS (retval)); ++ value_address (retval)); + } + return retval; + } +@@ -1465,6 +1625,8 @@ value_change_enclosing_type (struct value *val, struct type *new_encl_type) + val->contents = + (gdb_byte *) xrealloc (val->contents, TYPE_LENGTH (new_encl_type)); + ++ type_incref (new_encl_type); ++ type_decref (val->enclosing_type); + val->enclosing_type = new_encl_type; + return val; + } +@@ -1516,6 +1678,8 @@ value_primitive_field (struct value *arg1, int offset, + memcpy (value_contents_all_raw (v), value_contents_all_raw (arg1), + TYPE_LENGTH (value_enclosing_type (arg1))); + } ++ type_incref (type); ++ type_decref (v->type); + v->type = type; + v->offset = value_offset (arg1); + v->embedded_offset = (offset + value_embedded_offset (arg1) +@@ -1592,7 +1756,7 @@ value_fn_field (struct value **arg1p, struct fn_field *f, int j, struct type *ty + v = allocate_value (ftype); + if (sym) + { +- VALUE_ADDRESS (v) = BLOCK_START (SYMBOL_BLOCK_VALUE (sym)); ++ set_value_address (v, BLOCK_START (SYMBOL_BLOCK_VALUE (sym))); + } + else + { +@@ -1601,9 +1765,9 @@ value_fn_field (struct value **arg1p, struct fn_field *f, int j, struct type *ty + struct objfile *objfile = msymbol_objfile (msym); + struct gdbarch *gdbarch = get_objfile_arch (objfile); + +- VALUE_ADDRESS (v) +- = gdbarch_convert_from_func_ptr_addr +- (gdbarch, SYMBOL_VALUE_ADDRESS (msym), ¤t_target); ++ set_value_address (v, ++ gdbarch_convert_from_func_ptr_addr ++ (gdbarch, SYMBOL_VALUE_ADDRESS (msym), ¤t_target)); + } + + if (arg1p) +@@ -1750,6 +1914,41 @@ pack_long (gdb_byte *buf, struct type *type, LONGEST num) + } + + ++/* Pack NUM into BUF using a target format of TYPE. */ ++ ++void ++pack_unsigned_long (gdb_byte *buf, struct type *type, ULONGEST num) ++{ ++ int len; ++ ++ type = check_typedef (type); ++ len = TYPE_LENGTH (type); ++ ++ switch (TYPE_CODE (type)) ++ { ++ case TYPE_CODE_INT: ++ case TYPE_CODE_CHAR: ++ case TYPE_CODE_ENUM: ++ case TYPE_CODE_FLAGS: ++ case TYPE_CODE_BOOL: ++ case TYPE_CODE_RANGE: ++ case TYPE_CODE_MEMBERPTR: ++ store_unsigned_integer (buf, len, num); ++ break; ++ ++ case TYPE_CODE_REF: ++ case TYPE_CODE_PTR: ++ store_typed_address (buf, type, (CORE_ADDR) num); ++ break; ++ ++ default: ++ error (_("\ ++Unexpected type (%d) encountered for unsigned integer constant."), ++ TYPE_CODE (type)); ++ } ++} ++ ++ + /* Convert C numbers into newly allocated values. */ + + struct value * +@@ -1763,6 +1962,19 @@ value_from_longest (struct type *type, LONGEST num) + } + + ++/* Convert C unsigned numbers into newly allocated values. */ ++ ++struct value * ++value_from_ulongest (struct type *type, ULONGEST num) ++{ ++ struct value *val = allocate_value (type); ++ ++ pack_unsigned_long (value_contents_raw (val), type, num); ++ ++ return val; ++} ++ ++ + /* Create a value representing a pointer of type TYPE to the address + ADDR. */ + struct value * +@@ -1816,8 +2028,9 @@ value_from_contents_and_address (struct type *type, + set_value_lazy (v, 1); + else + memcpy (value_contents_raw (v), valaddr, TYPE_LENGTH (type)); +- VALUE_ADDRESS (v) = address; +- VALUE_LVAL (v) = lval_memory; ++ set_value_address (v, address); ++ if (address != 0) ++ VALUE_LVAL (v) = lval_memory; + return v; + } + +@@ -1944,4 +2157,15 @@ init-if-undefined VARIABLE = EXPRESSION\n\ + Set an internal VARIABLE to the result of the EXPRESSION if it does not\n\ + exist or does not contain a value. The EXPRESSION is not evaluated if the\n\ + VARIABLE is already initialized.")); ++ ++ add_prefix_cmd ("function", no_class, function_command, _("\ ++Placeholder command for showing help on convenience functions."), ++ &functionlist, "function ", 0, &cmdlist); ++ ++ internal_fn_type = alloc_type (OBJFILE_INTERNAL, NULL); ++ TYPE_CODE (internal_fn_type) = TYPE_CODE_INTERNAL_FUNCTION; ++ TYPE_LENGTH (internal_fn_type) = sizeof (struct internal_function *); ++ TYPE_NAME (internal_fn_type) = ""; ++ ++ make_final_cleanup (value_history_cleanup, NULL); + } +diff --git a/gdb/value.h b/gdb/value.h +index aa43365..1ad3c75 100644 +--- a/gdb/value.h ++++ b/gdb/value.h +@@ -272,12 +272,23 @@ extern void set_value_component_location (struct value *component, + extern enum lval_type *deprecated_value_lval_hack (struct value *); + #define VALUE_LVAL(val) (*deprecated_value_lval_hack (val)) + +-/* If lval == lval_memory, this is the address in the inferior. If +- lval == lval_register, this is the byte offset into the registers +- structure. */ ++/* Backward compatibility for the Fedora merge branch. */ + extern CORE_ADDR *deprecated_value_address_hack (struct value *); + #define VALUE_ADDRESS(val) (*deprecated_value_address_hack (val)) + ++/* If lval == lval_memory, return the address in the inferior. If ++ lval == lval_register, return the byte offset into the registers ++ structure. Otherwise, return 0. The returned address ++ includes the offset, if any. */ ++extern CORE_ADDR value_address (struct value *); ++ ++/* Like value_address, except the result does not include value's ++ offset. */ ++extern CORE_ADDR value_raw_address (struct value *); ++ ++/* Set the address of a value. */ ++extern void set_value_address (struct value *, CORE_ADDR); ++ + /* Pointer to internal variable. */ + extern struct internalvar **deprecated_value_internalvar_hack (struct value *); + #define VALUE_INTERNALVAR(val) (*deprecated_value_internalvar_hack (val)) +@@ -314,6 +325,9 @@ struct internalvar + struct value *value; + internalvar_make_value make_value; + int endian; ++ /* True if this internalvar is the canonical name for a convenience ++ function. */ ++ int canonical; + }; + + +@@ -342,12 +356,17 @@ extern LONGEST unpack_field_as_long (struct type *type, + extern void pack_long (gdb_byte *buf, struct type *type, LONGEST num); + + extern struct value *value_from_longest (struct type *type, LONGEST num); ++extern struct value *value_from_ulongest (struct type *type, ULONGEST num); + extern struct value *value_from_pointer (struct type *type, CORE_ADDR addr); + extern struct value *value_from_double (struct type *type, DOUBLEST num); + extern struct value *value_from_decfloat (struct type *type, + const gdb_byte *decbytes); + extern struct value *value_from_string (char *string); + ++extern const char *object_address_data_not_valid (struct type *type); ++extern int object_address_get_data (struct type *type, ++ CORE_ADDR *address_return); ++ + extern struct value *value_at (struct type *type, CORE_ADDR addr); + extern struct value *value_at_lazy (struct type *type, CORE_ADDR addr); + +@@ -388,6 +407,8 @@ extern struct value *value_mark (void); + + extern void value_free_to_mark (struct value *mark); + ++extern struct value *value_typed_string (char *ptr, int len, ++ struct type *char_type); + extern struct value *value_string (char *ptr, int len); + extern struct value *value_bitstring (char *ptr, int len); + +@@ -435,6 +456,7 @@ extern struct value *value_struct_elt (struct value **argp, + + extern struct value *value_aggregate_elt (struct type *curtype, + char *name, ++ struct type *expect_type, + int want_address, + enum noside noside); + +@@ -533,14 +555,14 @@ extern void set_internalvar_component (struct internalvar *var, + int bitpos, int bitsize, + struct value *newvalue); + +-extern struct internalvar *lookup_only_internalvar (char *name); ++extern struct internalvar *lookup_only_internalvar (const char *name); + +-extern struct internalvar *create_internalvar (char *name); ++extern struct internalvar *create_internalvar (const char *name); + + extern struct internalvar * + create_internalvar_type_lazy (char *name, internalvar_make_value fun); + +-extern struct internalvar *lookup_internalvar (char *name); ++extern struct internalvar *lookup_internalvar (const char *name); + + extern int value_equal (struct value *arg1, struct value *arg2); + +@@ -619,7 +641,7 @@ extern int common_val_print (struct value *val, + const struct value_print_options *options, + const struct language_defn *language); + +-extern int val_print_string (CORE_ADDR addr, int len, int width, ++extern int val_print_string (struct type *elttype, CORE_ADDR addr, int len, + struct ui_file *stream, + const struct value_print_options *options); + +@@ -658,5 +680,22 @@ extern struct value *value_allocate_space_in_inferior (int); + + extern struct value *value_of_local (const char *name, int complain); + +-extern struct value * value_subscripted_rvalue (struct value *array, struct value *idx, int lowerbound); ++extern struct value *value_subscripted_rvalue (struct value *array, ++ CORE_ADDR offset); ++ ++/* User function handler. */ ++ ++typedef struct value *(*internal_function_fn) (void *cookie, ++ int argc, ++ struct value **argv); ++ ++void add_internal_function (const char *name, const char *doc, ++ internal_function_fn handler, ++ void *cookie); ++ ++struct value *call_internal_function (struct value *function, ++ int argc, struct value **argv); ++ ++char *value_internal_function_name (struct value *); ++ + #endif /* !defined (VALUE_H) */ +diff --git a/gdb/varobj.c b/gdb/varobj.c +index 2ec6d90..1237c96 100644 +--- a/gdb/varobj.c ++++ b/gdb/varobj.c +@@ -29,11 +29,20 @@ + + #include "gdb_assert.h" + #include "gdb_string.h" ++#include "gdb_regex.h" + + #include "varobj.h" + #include "vec.h" + #include "gdbthread.h" + #include "inferior.h" ++#include "valprint.h" ++ ++#if HAVE_PYTHON ++#include "python/python.h" ++#include "python/python-internal.h" ++#else ++typedef int PyObject; ++#endif + + /* Non-zero if we want to see trace of varobj level stuff. */ + +@@ -138,6 +147,12 @@ struct varobj + /* Children of this object. */ + VEC (varobj_p) *children; + ++ /* Whether the children of this varobj were requested. This field is ++ used to decide if dynamic varobj should recompute their children. ++ In the event that the frontend never asked for the children, we ++ can avoid that. */ ++ int children_requested; ++ + /* Description of the root variable. Points to root variable for children. */ + struct varobj_root *root; + +@@ -159,6 +174,16 @@ struct varobj + not fetched if either the variable is frozen, or any parents is + frozen. */ + int not_fetched; ++ ++ /* Sub-range of children which the MI consumer has requested. If ++ FROM < 0 or TO < 0, means that all children have been ++ requested. */ ++ int from; ++ int to; ++ ++ /* The pretty-printer that has been constructed. If NULL, then a ++ new printer object is needed, and one will be constructed. */ ++ PyObject *pretty_printer; + }; + + struct cpstack +@@ -190,6 +215,10 @@ static void uninstall_variable (struct varobj *); + + static struct varobj *create_child (struct varobj *, int, char *); + ++static struct varobj * ++create_child_with_value (struct varobj *parent, int index, const char *name, ++ struct value *value); ++ + /* Utility routines */ + + static struct varobj *new_variable (void); +@@ -200,6 +229,8 @@ static void free_variable (struct varobj *var); + + static struct cleanup *make_cleanup_free_variable (struct varobj *var); + ++static struct cleanup *make_cleanup_uninstall_variable (struct varobj *var); ++ + static struct type *get_type (struct varobj *var); + + static struct type *get_value_type (struct varobj *var); +@@ -215,6 +246,8 @@ static char *cppop (struct cpstack **pstack); + static int install_new_value (struct varobj *var, struct value *value, + int initial); + ++static void install_default_visualizer (struct varobj *var); ++ + /* Language-specific routines. */ + + static enum varobj_languages variable_language (struct varobj *var); +@@ -232,13 +265,17 @@ static struct value *value_of_child (struct varobj *parent, int index); + static char *my_value_of_variable (struct varobj *var, + enum varobj_display_formats format); + +-static char *value_get_print_value (struct value *value, +- enum varobj_display_formats format); ++char *value_get_print_value (struct value *value, ++ enum varobj_display_formats format, ++ PyObject *value_formatter); + + static int varobj_value_is_changeable_p (struct varobj *var); + + static int is_root_p (struct varobj *var); + ++static struct varobj * ++varobj_add_child (struct varobj *var, const char *name, struct value *value); ++ + /* C implementation */ + + static int c_number_of_children (struct varobj *var); +@@ -570,8 +607,10 @@ varobj_create (char *objname, + do_cleanups (old_chain); + return NULL; + } ++ make_cleanup_uninstall_variable (var); + } + ++ install_default_visualizer (var); + discard_cleanups (old_chain); + return var; + } +@@ -678,6 +717,33 @@ varobj_delete (struct varobj *var, char ***dellist, int only_children) + return delcount; + } + ++/* Convenience function for varobj_set_visualizer. Instantiate a ++ pretty-printer for a given value. */ ++static PyObject * ++instantiate_pretty_printer (PyObject *constructor, struct value *value) ++{ ++#if HAVE_PYTHON ++ PyObject *val_obj = NULL; ++ PyObject *printer; ++ volatile struct gdb_exception except; ++ ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ value = value_copy (value); ++ } ++ GDB_PY_HANDLE_EXCEPTION (except); ++ val_obj = value_to_value_object (value); ++ ++ if (! val_obj) ++ return NULL; ++ ++ printer = gdbpy_instantiate_printer (constructor, val_obj); ++ Py_DECREF (val_obj); ++ return printer; ++#endif ++ return NULL; ++} ++ + /* Set/Get variable object display format */ + + enum varobj_display_formats +@@ -702,7 +768,8 @@ varobj_set_display_format (struct varobj *var, + && var->value && !value_lazy (var->value)) + { + xfree (var->print_value); +- var->print_value = value_get_print_value (var->value, var->format); ++ var->print_value = value_get_print_value (var->value, var->format, ++ var->pretty_printer); + } + + return var->format; +@@ -714,6 +781,21 @@ varobj_get_display_format (struct varobj *var) + return var->format; + } + ++char * ++varobj_get_display_hint (struct varobj *var) ++{ ++ char *result = NULL; ++ ++#if HAVE_PYTHON ++ PyGILState_STATE state = PyGILState_Ensure (); ++ if (var->pretty_printer) ++ result = gdbpy_get_display_hint (var->pretty_printer); ++ PyGILState_Release (state); ++#endif ++ ++ return result; ++} ++ + /* If the variable object is bound to a specific thread, that + is its evaluation can always be done in context of a frame + inside that thread, returns GDB id of the thread -- which +@@ -746,12 +828,141 @@ varobj_get_frozen (struct varobj *var) + return var->frozen; + } + ++static int ++update_dynamic_varobj_children (struct varobj *var, ++ VEC (varobj_p) **changed, ++ VEC (varobj_p) **new_and_unchanged, ++ int *cchanged) ++ ++{ ++#if HAVE_PYTHON ++ /* FIXME: we *might* want to provide this functionality as ++ a standalone function, so that other interested parties ++ than varobj code can benefit for this. */ ++ struct cleanup *back_to; ++ PyObject *children; ++ PyObject *iterator; ++ int i; ++ int children_changed = 0; ++ PyObject *printer = var->pretty_printer; ++ PyGILState_STATE state; ++ ++ state = PyGILState_Ensure (); ++ back_to = make_cleanup_py_restore_gil (&state); ++ ++ *cchanged = 0; ++ if (!PyObject_HasAttr (printer, gdbpy_children_cst)) ++ { ++ do_cleanups (back_to); ++ return 0; ++ } ++ ++ children = PyObject_CallMethodObjArgs (printer, gdbpy_children_cst, ++ NULL); ++ ++ if (!children) ++ { ++ gdbpy_print_stack (); ++ error ("Null value returned for children"); ++ } ++ ++ make_cleanup_py_decref (children); ++ ++ if (!PyIter_Check (children)) ++ error ("Returned value is not iterable"); ++ ++ iterator = PyObject_GetIter (children); ++ if (!iterator) ++ { ++ gdbpy_print_stack (); ++ error ("Could not get children iterator"); ++ } ++ make_cleanup_py_decref (iterator); ++ ++ for (i = 0; ; ++i) ++ { ++ PyObject *item = PyIter_Next (iterator); ++ PyObject *py_v; ++ struct value *v; ++ char *name; ++ struct cleanup *inner; ++ ++ if (!item) ++ break; ++ inner = make_cleanup_py_decref (item); ++ ++ if (!PyArg_ParseTuple (item, "sO", &name, &py_v)) ++ error ("Invalid item from the child list"); ++ ++ if (PyObject_TypeCheck (py_v, &value_object_type)) ++ { ++ /* If we just call convert_value_from_python for this type, ++ we won't know who owns the result. For this one case we ++ need to copy the resulting value. */ ++ v = value_object_to_value (py_v); ++ v = value_copy (v); ++ } ++ else ++ v = convert_value_from_python (py_v); ++ ++ /* TODO: This assume the name of the i-th child never changes. */ ++ ++ /* Now see what to do here. */ ++ if (VEC_length (varobj_p, var->children) < i + 1) ++ { ++ /* There's no child yet. */ ++ struct varobj *child = varobj_add_child (var, name, v); ++ if (new_and_unchanged) ++ VEC_safe_push (varobj_p, *new_and_unchanged, child); ++ children_changed = 1; ++ } ++ else ++ { ++ varobj_p existing = VEC_index (varobj_p, var->children, i); ++ if (install_new_value (existing, v, 0) && changed) ++ { ++ if (changed) ++ VEC_safe_push (varobj_p, *changed, existing); ++ } ++ else ++ { ++ if (new_and_unchanged) ++ VEC_safe_push (varobj_p, *new_and_unchanged, existing); ++ } ++ } ++ ++ do_cleanups (inner); ++ } ++ ++ if (i < VEC_length (varobj_p, var->children)) ++ { ++ int i; ++ children_changed = 1; ++ for (i = 0; i < VEC_length (varobj_p, var->children); ++i) ++ varobj_delete (VEC_index (varobj_p, var->children, i), NULL, 0); ++ } ++ VEC_truncate (varobj_p, var->children, i); ++ var->num_children = VEC_length (varobj_p, var->children); ++ ++ do_cleanups (back_to); ++ ++ *cchanged = children_changed; ++ return 1; ++#else ++ gdb_assert (0 && "should never be called if Python is not enabled"); ++#endif ++} + + int + varobj_get_num_children (struct varobj *var) + { + if (var->num_children == -1) +- var->num_children = number_of_children (var); ++ { ++ int changed; ++ if (!var->pretty_printer ++ || !update_dynamic_varobj_children (var, NULL, NULL, &changed)) ++ var->num_children = number_of_children (var); ++ } + + return var->num_children; + } +@@ -764,7 +975,16 @@ varobj_list_children (struct varobj *var) + { + struct varobj *child; + char *name; +- int i; ++ int i, children_changed; ++ ++ var->children_requested = 1; ++ ++ if (var->pretty_printer ++ /* This, in theory, can result in the number of children changing without ++ frontend noticing. But well, calling -var-list-children on the same ++ varobj twice is not something a sane frontend would do. */ ++ && update_dynamic_varobj_children (var, NULL, NULL, &children_changed)) ++ return var->children; + + if (var->num_children == -1) + var->num_children = number_of_children (var); +@@ -790,12 +1010,24 @@ varobj_list_children (struct varobj *var) + name = name_of_child (var, i); + existing = create_child (var, i, name); + VEC_replace (varobj_p, var->children, i, existing); ++ install_default_visualizer (existing); + } + } + + return var->children; + } + ++static struct varobj * ++varobj_add_child (struct varobj *var, const char *name, struct value *value) ++{ ++ varobj_p v = create_child_with_value (var, ++ VEC_length (varobj_p, var->children), ++ name, value); ++ VEC_safe_push (varobj_p, var->children, v); ++ install_default_visualizer (v); ++ return v; ++} ++ + /* Obtain the type of an object Variable as a string similar to the one gdb + prints on the console */ + +@@ -1002,6 +1234,13 @@ install_new_value (struct varobj *var, struct value *value, int initial) + a type. */ + gdb_assert (var->type || CPLUS_FAKE_CHILD (var)); + changeable = varobj_value_is_changeable_p (var); ++ ++ /* If the type has custom visualizer, we consider it to be always ++ changeable. FIXME: need to make sure this behaviour will not ++ mess up read-sensitive values. */ ++ if (var->pretty_printer) ++ changeable = 1; ++ + need_to_fetch = changeable; + + /* We are not interested in the address of references, and given +@@ -1053,12 +1292,14 @@ install_new_value (struct varobj *var, struct value *value, int initial) + } + } + ++ + /* Below, we'll be comparing string rendering of old and new + values. Don't get string rendering if the value is + lazy -- if it is, the code above has decided that the value + should not be fetched. */ + if (value && !value_lazy (value)) +- print_value = value_get_print_value (value, var->format); ++ print_value = value_get_print_value (value, var->format, ++ var->pretty_printer); + + /* If the type is changeable, compare the old and the new values. + If this is the initial assignment, we don't have any old value +@@ -1123,6 +1364,150 @@ install_new_value (struct varobj *var, struct value *value, int initial) + return changed; + } + ++/* Return the effective requested range for a varobj. VAR is the ++ varobj. CHILDREN is the computed list of children. FROM and TO ++ are out parameters. If VAR has no bounds selected, *FROM and *TO ++ will be set to the full range of CHILDREN. Otherwise, *FROM and ++ *TO will be set to the selected sub-range of VAR, clipped to be in ++ range of CHILDREN. */ ++void ++varobj_get_child_range (struct varobj *var, VEC (varobj_p) *children, ++ int *from, int *to) ++{ ++ if (var->from < 0 || var->to < 0) ++ { ++ *from = 0; ++ *to = VEC_length (varobj_p, children); ++ } ++ else ++ { ++ *from = var->from; ++ if (*from > VEC_length (varobj_p, children)) ++ *from = VEC_length (varobj_p, children); ++ *to = var->to; ++ if (*to > VEC_length (varobj_p, children)) ++ *to = VEC_length (varobj_p, children); ++ } ++} ++ ++/* Set the selected sub-range of children of VAR to start at index ++ FROM and end at index TO. If either FROM or TO is less than zero, ++ this is interpreted as a request for all children. */ ++void ++varobj_set_child_range (struct varobj *var, int from, int to) ++{ ++ var->from = from; ++ var->to = to; ++} ++ ++static void ++install_visualizer (struct varobj *var, PyObject *visualizer) ++{ ++#if HAVE_PYTHON ++ /* If there are any children now, wipe them. */ ++ varobj_delete (var, NULL, 1 /* children only */); ++ var->num_children = -1; ++ ++ Py_XDECREF (var->pretty_printer); ++ var->pretty_printer = visualizer; ++ ++ install_new_value (var, var->value, 1); ++ ++ /* If we removed the visualizer, and the user ever requested the ++ object's children, then we must compute the list of children. ++ Note that we needn't do this when installing a visualizer, ++ because updating will recompute dynamic children. */ ++ if (!visualizer && var->children_requested) ++ varobj_list_children (var); ++#else ++ error ("Python support required"); ++#endif ++} ++ ++static void ++install_default_visualizer (struct varobj *var) ++{ ++#if HAVE_PYTHON ++ struct cleanup *cleanup; ++ PyGILState_STATE state; ++ PyObject *pretty_printer = NULL; ++ ++ state = PyGILState_Ensure (); ++ cleanup = make_cleanup_py_restore_gil (&state); ++ ++ if (var->value) ++ { ++ pretty_printer = gdbpy_get_varobj_pretty_printer (var->value); ++ if (! pretty_printer) ++ { ++ gdbpy_print_stack (); ++ error (_("Cannot instantiate printer for default visualizer")); ++ } ++ } ++ ++ if (pretty_printer == Py_None) ++ { ++ Py_DECREF (pretty_printer); ++ pretty_printer = NULL; ++ } ++ ++ install_visualizer (var, pretty_printer); ++ do_cleanups (cleanup); ++#else ++ /* No error is right as this function is inserted just as a hook. */ ++#endif ++} ++ ++void ++varobj_set_visualizer (struct varobj *var, const char *visualizer) ++{ ++#if HAVE_PYTHON ++ PyObject *mainmod, *globals, *pretty_printer, *constructor; ++ struct cleanup *back_to, *value; ++ PyGILState_STATE state; ++ ++ ++ state = PyGILState_Ensure (); ++ back_to = make_cleanup_py_restore_gil (&state); ++ ++ mainmod = PyImport_AddModule ("__main__"); ++ globals = PyModule_GetDict (mainmod); ++ Py_INCREF (globals); ++ make_cleanup_py_decref (globals); ++ ++ constructor = PyRun_String (visualizer, Py_eval_input, globals, globals); ++ ++ /* Do not instantiate NoneType. */ ++ if (constructor == Py_None) ++ { ++ pretty_printer = Py_None; ++ Py_INCREF (pretty_printer); ++ } ++ else ++ pretty_printer = instantiate_pretty_printer (constructor, var->value); ++ ++ Py_XDECREF (constructor); ++ ++ if (! pretty_printer) ++ { ++ gdbpy_print_stack (); ++ error ("Could not evaluate visualizer expression: %s", visualizer); ++ } ++ ++ if (pretty_printer == Py_None) ++ { ++ Py_DECREF (pretty_printer); ++ pretty_printer = NULL; ++ } ++ ++ install_visualizer (var, pretty_printer); ++ ++ do_cleanups (back_to); ++#else ++ error ("Python support required"); ++#endif ++} ++ + /* 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 +@@ -1148,7 +1533,7 @@ VEC(varobj_update_result) *varobj_update (struct varobj **varp, int explicit) + struct varobj **cv; + struct varobj **templist = NULL; + struct value *new; +- VEC (varobj_p) *stack = NULL; ++ VEC (varobj_update_result) *stack = NULL; + VEC (varobj_update_result) *result = NULL; + struct frame_info *fi; + +@@ -1187,20 +1572,85 @@ VEC(varobj_update_result) *varobj_update (struct varobj **varp, int explicit) + + if (new == NULL) + r.status = VAROBJ_NOT_IN_SCOPE; +- +- if (r.type_changed || r.changed) +- VEC_safe_push (varobj_update_result, result, &r); ++ r.value_installed = 1; + + if (r.status == VAROBJ_NOT_IN_SCOPE) +- return result; ++ { ++ VEC_safe_push (varobj_update_result, result, &r); ++ return result; ++ } ++ ++ VEC_safe_push (varobj_update_result, stack, &r); ++ } ++ else ++ { ++ varobj_update_result r = {*varp}; ++ VEC_safe_push (varobj_update_result, stack, &r); + } +- +- VEC_safe_push (varobj_p, stack, *varp); + + /* Walk through the children, reconstructing them all. */ +- while (!VEC_empty (varobj_p, stack)) ++ while (!VEC_empty (varobj_update_result, stack)) + { +- v = VEC_pop (varobj_p, stack); ++ varobj_update_result r = *(VEC_last (varobj_update_result, stack)); ++ struct varobj *v = r.varobj; ++ ++ VEC_pop (varobj_update_result, stack); ++ ++ /* Update this variable, unless it's a root, which is already ++ updated. */ ++ if (!r.value_installed) ++ { ++ new = value_of_child (v->parent, v->index); ++ if (install_new_value (v, new, 0 /* type not changed */)) ++ { ++ r.changed = 1; ++ v->updated = 0; ++ } ++ } ++ ++ /* We probably should not get children of a varobj that has a ++ pretty-printer, but for which -var-list-children was never ++ invoked. Presumably, such varobj is not yet expanded in the ++ UI, so we need not bother getting it. */ ++ if (v->pretty_printer) ++ { ++ VEC (varobj_p) *changed = 0, *new_and_unchanged = 0; ++ int i, children_changed; ++ varobj_p tmp; ++ ++ if (!v->children_requested) ++ continue; ++ ++ if (v->frozen) ++ continue; ++ ++ /* If update_dynamic_varobj_children returns 0, then we have ++ a non-conforming pretty-printer, so we skip it. */ ++ if (update_dynamic_varobj_children (v, &changed, &new_and_unchanged, ++ &children_changed)) ++ { ++ if (children_changed) ++ r.children_changed = 1; ++ for (i = 0; VEC_iterate (varobj_p, changed, i, tmp); ++i) ++ { ++ varobj_update_result r = {tmp}; ++ r.changed = 1; ++ r.value_installed = 1; ++ VEC_safe_push (varobj_update_result, stack, &r); ++ } ++ for (i = 0; ++ VEC_iterate (varobj_p, new_and_unchanged, i, tmp); ++ ++i) ++ { ++ varobj_update_result r = {tmp}; ++ r.value_installed = 1; ++ VEC_safe_push (varobj_update_result, stack, &r); ++ } ++ if (r.changed || r.children_changed) ++ VEC_safe_push (varobj_update_result, result, &r); ++ continue; ++ } ++ } + + /* Push any children. Use reverse order so that the first + child is popped from the work stack first, and so +@@ -1211,26 +1661,18 @@ VEC(varobj_update_result) *varobj_update (struct varobj **varp, int explicit) + varobj_p c = VEC_index (varobj_p, v->children, i); + /* Child may be NULL if explicitly deleted by -var-delete. */ + if (c != NULL && !c->frozen) +- VEC_safe_push (varobj_p, stack, c); +- } +- +- /* Update this variable, unless it's a root, which is already +- updated. */ +- if (v->root->rootvar != v) +- { +- new = value_of_child (v->parent, v->index); +- if (install_new_value (v, new, 0 /* type not changed */)) + { +- /* Note that it's changed */ +- varobj_update_result r = {v}; +- r.changed = 1; +- VEC_safe_push (varobj_update_result, result, &r); +- v->updated = 0; ++ varobj_update_result r = {c}; ++ VEC_safe_push (varobj_update_result, stack, &r); + } + } ++ ++ if (r.changed || r.type_changed) ++ VEC_safe_push (varobj_update_result, result, &r); + } + +- VEC_free (varobj_p, stack); ++ VEC_free (varobj_update_result, stack); ++ + return result; + } + +@@ -1429,16 +1871,23 @@ uninstall_variable (struct varobj *var) + static struct varobj * + create_child (struct varobj *parent, int index, char *name) + { ++ return create_child_with_value (parent, index, name, ++ value_of_child (parent, index)); ++} ++ ++static struct varobj * ++create_child_with_value (struct varobj *parent, int index, const char *name, ++ struct value *value) ++{ + struct varobj *child; + char *childs_name; +- struct value *value; + + child = new_variable (); + + /* name is allocated by name_of_child */ +- child->name = name; ++ /* FIXME: xstrdup should not be here. */ ++ child->name = xstrdup (name); + child->index = index; +- value = value_of_child (parent, index); + child->parent = parent; + child->root = parent->root; + childs_name = xstrprintf ("%s.%s", parent->obj_name, name); +@@ -1487,6 +1936,10 @@ new_variable (void) + var->print_value = NULL; + var->frozen = 0; + var->not_fetched = 0; ++ var->children_requested = 0; ++ var->from = -1; ++ var->to = -1; ++ var->pretty_printer = 0; + + return var; + } +@@ -1519,6 +1972,14 @@ free_variable (struct varobj *var) + xfree (var->root); + } + ++#if HAVE_PYTHON ++ { ++ PyGILState_STATE state = PyGILState_Ensure (); ++ Py_XDECREF (var->pretty_printer); ++ PyGILState_Release (state); ++ } ++#endif ++ + xfree (var->name); + xfree (var->obj_name); + xfree (var->print_value); +@@ -1538,6 +1999,18 @@ make_cleanup_free_variable (struct varobj *var) + return make_cleanup (do_free_variable_cleanup, var); + } + ++static void ++do_uninstall_variable_cleanup (void *var) ++{ ++ uninstall_variable (var); ++} ++ ++static struct cleanup * ++make_cleanup_uninstall_variable (struct varobj *var) ++{ ++ return make_cleanup (do_uninstall_variable_cleanup, var); ++} ++ + /* This returns the type of the variable. It also skips past typedefs + to return the real type of the variable. + +@@ -1792,24 +2265,71 @@ my_value_of_variable (struct varobj *var, enum varobj_display_formats format) + return NULL; + } + +-static char * +-value_get_print_value (struct value *value, enum varobj_display_formats format) ++char * ++value_get_print_value (struct value *value, enum varobj_display_formats format, ++ PyObject *value_formatter) + { + long dummy; + struct ui_file *stb; + struct cleanup *old_chain; +- char *thevalue; ++ char *thevalue = NULL; + struct value_print_options opts; + + if (value == NULL) + return NULL; + ++#if HAVE_PYTHON ++ { ++ PyGILState_STATE state = PyGILState_Ensure (); ++ if (value_formatter && PyObject_HasAttr (value_formatter, ++ gdbpy_to_string_cst)) ++ { ++ char *hint; ++ struct value *replacement; ++ int string_print = 0; ++ ++ hint = gdbpy_get_display_hint (value_formatter); ++ if (hint) ++ { ++ if (!strcmp (hint, "string")) ++ string_print = 1; ++ xfree (hint); ++ } ++ ++ thevalue = apply_varobj_pretty_printer (value_formatter, ++ &replacement); ++ if (thevalue && !string_print) ++ { ++ PyGILState_Release (state); ++ return thevalue; ++ } ++ if (replacement) ++ value = replacement; ++ } ++ PyGILState_Release (state); ++ } ++#endif ++ + stb = mem_fileopen (); + old_chain = make_cleanup_ui_file_delete (stb); + + get_formatted_print_options (&opts, format_code[(int) format]); + opts.deref_ref = 0; +- common_val_print (value, stb, 0, &opts, current_language); ++ opts.raw = 1; ++ if (thevalue) ++ { ++ struct type *string_char_type; ++ ++ make_cleanup (xfree, thevalue); ++ ++ /* OUTPUT is already in the hosts's charset. */ ++ string_char_type = language_string_char_type (current_language, ++ current_gdbarch); ++ LA_PRINT_STRING (stb, string_char_type, (gdb_byte *) thevalue, ++ strlen (thevalue), 0, &opts); ++ } ++ else ++ common_val_print (value, stb, 0, &opts, current_language); + thevalue = ui_file_xstrdup (stb, &dummy); + + do_cleanups (old_chain); +@@ -1900,7 +2420,7 @@ varobj_floating_p (struct varobj *var) + value is not known. + + If WAS_PTR is not NULL, set *WAS_PTR to 0 or 1 +- depending on whether pointer was deferenced ++ depending on whether pointer was dereferenced + in this function. */ + static void + adjust_value_for_child_access (struct value **value, +@@ -2269,6 +2789,11 @@ c_value_of_variable (struct varobj *var, enum varobj_display_formats format) + catch that case explicitly. */ + struct type *type = get_type (var); + ++ /* If we have a custom formatter, return whatever string it has ++ produced. */ ++ if (var->pretty_printer && var->print_value) ++ return xstrdup (var->print_value); ++ + /* Strip top-level references. */ + while (TYPE_CODE (type) == TYPE_CODE_REF) + type = check_typedef (TYPE_TARGET_TYPE (type)); +@@ -2313,7 +2838,8 @@ c_value_of_variable (struct varobj *var, enum varobj_display_formats format) + if (format == var->format) + return xstrdup (var->print_value); + else +- return value_get_print_value (var->value, format); ++ return value_get_print_value (var->value, format, ++ var->pretty_printer); + } + } + } +diff --git a/gdb/varobj.h b/gdb/varobj.h +index f2cdcf8..10758d6 100644 +--- a/gdb/varobj.h ++++ b/gdb/varobj.h +@@ -72,7 +72,12 @@ typedef struct varobj_update_result_t + struct varobj *varobj; + int type_changed; + int changed; ++ int children_changed; + enum varobj_scope_status status; ++ /* This variable is used internally by varobj_update to indicate if the ++ new value of varobj is already computed and installed, or has to ++ be yet installed. Don't use this outside varobj.c */ ++ int value_installed; + } varobj_update_result; + + DEF_VEC_O (varobj_update_result); +@@ -107,6 +112,14 @@ extern void varobj_set_frozen (struct varobj *var, int frozen); + + extern int varobj_get_frozen (struct varobj *var); + ++extern void varobj_get_child_range (struct varobj *var, ++ VEC (varobj_p) *children, ++ int *from, int *to); ++ ++extern void varobj_set_child_range (struct varobj *var, int from, int to); ++ ++extern char *varobj_get_display_hint (struct varobj *var); ++ + extern int varobj_get_num_children (struct varobj *var); + + /* Return the list of children of VAR. The returned vector +@@ -141,4 +154,13 @@ extern int varobj_editable_p (struct varobj *var); + + extern int varobj_floating_p (struct varobj *var); + ++extern void ++varobj_set_visualizer (struct varobj *var, const char *visualizer); ++ ++extern void ++varobj_clear_type_visualizers (); ++ ++extern void ++varobj_set_visualizer (struct varobj *var, const char *visualizer); ++ + #endif /* VAROBJ_H */ +diff --git a/gdb/xcoffread.c b/gdb/xcoffread.c +index aab3e48..d41738b 100644 +--- a/gdb/xcoffread.c ++++ b/gdb/xcoffread.c +@@ -3021,6 +3021,7 @@ static struct sym_fns xcoff_sym_fns = + xcoff_new_init, /* sym_new_init: init anything gbl to entire symtab */ + xcoff_symfile_init, /* sym_init: read initial info, setup for sym_read() */ + xcoff_initial_scan, /* sym_read: read a symbol file into symtab */ ++ NULL, /* sym_read_psymbols */ + xcoff_symfile_finish, /* sym_finish: finished with file, cleanup */ + xcoff_symfile_offsets, /* sym_offsets: xlate offsets ext->int form */ + default_symfile_segments, /* sym_segments: Get segment information from +diff --git a/gdb/xml-syscall.c b/gdb/xml-syscall.c +new file mode 100644 +index 0000000..498f58a +--- /dev/null ++++ b/gdb/xml-syscall.c +@@ -0,0 +1,423 @@ ++/* Functions that provide the mechanism to parse a syscall XML file ++ and get its values. ++ ++ Copyright (C) 1986, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, ++ 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007, 2008 ++ Free Software Foundation, Inc. ++ ++ This file is part of GDB. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++#include "defs.h" ++#include "gdbtypes.h" ++#include "xml-support.h" ++#include "xml-syscall.h" ++ ++#include "filenames.h" ++ ++#include "gdb_assert.h" ++ ++#ifndef HAVE_LIBEXPAT ++ ++/* Dummy functions to indicate that there's no support for fetching ++ syscalls information. */ ++ ++static void ++syscall_warn_user (void) ++{ ++ static int have_warned = 0; ++ if (!have_warned) ++ { ++ have_warned = 1; ++ warning (_("Can not parse XML syscalls information; XML support was " ++ "disabled at compile time")); ++ } ++} ++ ++const struct syscalls_info * ++xml_init_syscalls_info (const char *filename) ++{ ++ syscall_warn_user (); ++ return NULL; ++} ++ ++int ++xml_get_syscall_number (const struct syscalls_info *sysinfo, ++ const char *syscall_name) ++{ ++ syscall_warn_user (); ++ return UNKNOWN_SYSCALL; ++} ++ ++const char * ++xml_get_syscall_name (const struct syscalls_info *sysinfo, ++ int syscall_number) ++{ ++ syscall_warn_user (); ++ return NULL; ++} ++ ++int ++xml_number_of_syscalls (const struct syscalls_info *sysinfo) ++{ ++ syscall_warn_user (); ++ return 0; ++} ++ ++const char ** ++xml_list_of_syscalls (const struct syscalls_info *sysinfo) ++{ ++ syscall_warn_user (); ++ return NULL; ++} ++ ++#else ++ ++/* Structure which describes a syscall. */ ++ ++typedef struct syscall_desc ++{ ++ /* The syscall number. */ ++ ++ int number; ++ ++ /* The syscall name. */ ++ ++ char *name; ++} *syscall_desc_p; ++DEF_VEC_P(syscall_desc_p); ++ ++/* Structure that represents syscalls information. */ ++ ++struct syscalls_info ++{ ++ /* The syscalls. */ ++ ++ VEC(syscall_desc_p) *syscalls; ++}; ++ ++/* Callback data for syscall information parsing. */ ++ ++struct syscall_parsing_data ++{ ++ /* The syscalls_info we are building. */ ++ ++ struct syscalls_info *sysinfo; ++}; ++ ++ ++static struct syscalls_info * ++allocate_syscalls_info (void) ++{ ++ return XZALLOC (struct syscalls_info); ++} ++ ++static void ++sysinfo_free_syscalls_desc (struct syscall_desc *sd) ++{ ++ xfree (sd->name); ++} ++ ++static void ++free_syscalls_info (void *arg) ++{ ++ struct syscalls_info *sysinfo = arg; ++ struct syscall_desc *sysdesc; ++ int i; ++ ++ for (i = 0; ++ VEC_iterate (syscall_desc_p, sysinfo->syscalls, i, sysdesc); ++ i++) ++ sysinfo_free_syscalls_desc (sysdesc); ++ VEC_free (syscall_desc_p, sysinfo->syscalls); ++ ++ xfree (sysinfo); ++} ++ ++struct cleanup * ++make_cleanup_free_syscalls_info (struct syscalls_info *sysinfo) ++{ ++ return make_cleanup (free_syscalls_info, sysinfo); ++} ++ ++/* Open FILENAME, read all its text into memory, close it, and return ++ the text. If something goes wrong, return NULL and warn. */ ++ ++static char * ++fetch_xml_from_file (const char *filename, void *baton) ++{ ++ const char *dirname = baton; ++ FILE *file; ++ struct cleanup *back_to; ++ char *text; ++ size_t len, offset; ++ ++ if (dirname && *dirname) ++ { ++ char *fullname = concat (dirname, "/", filename, (char *) NULL); ++ if (fullname == NULL) ++ nomem (0); ++ file = fopen (fullname, FOPEN_RT); ++ xfree (fullname); ++ } ++ else ++ file = fopen (filename, FOPEN_RT); ++ ++ if (file == NULL) ++ return NULL; ++ ++ back_to = make_cleanup_fclose (file); ++ ++ /* Read in the whole file, one chunk at a time. */ ++ len = 4096; ++ offset = 0; ++ text = xmalloc (len); ++ make_cleanup (free_current_contents, &text); ++ while (1) ++ { ++ size_t bytes_read; ++ ++ /* Continue reading where the last read left off. Leave at least ++ one byte so that we can NUL-terminate the result. */ ++ bytes_read = fread (text + offset, 1, len - offset - 1, file); ++ if (ferror (file)) ++ { ++ warning (_("Read error from \"%s\""), filename); ++ do_cleanups (back_to); ++ return NULL; ++ } ++ ++ offset += bytes_read; ++ ++ if (feof (file)) ++ break; ++ ++ len = len * 2; ++ text = xrealloc (text, len); ++ } ++ ++ fclose (file); ++ discard_cleanups (back_to); ++ ++ text[offset] = '\0'; ++ return text; ++} ++ ++static void ++syscall_create_syscall_desc (struct syscalls_info *sysinfo, ++ const char *name, int number) ++{ ++ struct syscall_desc *sysdesc = XZALLOC (struct syscall_desc); ++ ++ sysdesc->name = xstrdup (name); ++ sysdesc->number = number; ++ ++ VEC_safe_push (syscall_desc_p, sysinfo->syscalls, sysdesc); ++} ++ ++/* Handle the start of a element. */ ++ ++static void ++syscall_start_syscalls_info (struct gdb_xml_parser *parser, ++ const struct gdb_xml_element *element, ++ void *user_data, ++ VEC(gdb_xml_value_s) *attributes) ++{ ++ struct syscall_parsing_data *data = user_data; ++ struct syscalls_info *sysinfo = data->sysinfo; ++} ++ ++/* Handle the start of a element. */ ++ ++static void ++syscall_start_syscall (struct gdb_xml_parser *parser, ++ const struct gdb_xml_element *element, ++ void *user_data, VEC(gdb_xml_value_s) *attributes) ++{ ++ struct syscall_parsing_data *data = user_data; ++ struct gdb_xml_value *attrs = VEC_address (gdb_xml_value_s, attributes); ++ int len, i; ++ /* syscall info. */ ++ char *name = NULL; ++ int number = 0; ++ ++ len = VEC_length (gdb_xml_value_s, attributes); ++ ++ for (i = 0; i < len; i++) ++ { ++ if (strcmp (attrs[i].name, "name") == 0) ++ name = attrs[i].value; ++ else if (strcmp (attrs[i].name, "number") == 0) ++ number = * (ULONGEST *) attrs[i].value; ++ else ++ internal_error (__FILE__, __LINE__, ++ _("Unknown attribute name '%s'."), attrs[i].name); ++ } ++ ++ syscall_create_syscall_desc (data->sysinfo, name, number); ++} ++ ++ ++/* The elements and attributes of an XML syscall document. */ ++ ++static const struct gdb_xml_attribute syscall_attr[] = { ++ { "number", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, ++ { "name", GDB_XML_AF_NONE, NULL, NULL }, ++ { NULL, GDB_XML_AF_NONE, NULL, NULL } ++}; ++ ++static const struct gdb_xml_element syscalls_info_children[] = { ++ { "syscall", syscall_attr, NULL, ++ GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE, ++ syscall_start_syscall, NULL }, ++ { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL } ++}; ++ ++static const struct gdb_xml_element syselements[] = { ++ { "syscalls_info", NULL, syscalls_info_children, ++ GDB_XML_EF_NONE, syscall_start_syscalls_info, NULL }, ++ { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL } ++}; ++ ++static struct syscalls_info * ++syscall_parse_xml (const char *document, xml_fetch_another fetcher, ++ void *fetcher_baton) ++{ ++ struct cleanup *result_cleanup; ++ struct gdb_xml_parser *parser; ++ struct syscall_parsing_data data; ++ char *expanded_text; ++ int i; ++ ++ parser = gdb_xml_create_parser_and_cleanup (_("syscalls info"), ++ syselements, &data); ++ ++ memset (&data, 0, sizeof (struct syscall_parsing_data)); ++ data.sysinfo = allocate_syscalls_info (); ++ result_cleanup = make_cleanup_free_syscalls_info (data.sysinfo); ++ ++ if (gdb_xml_parse (parser, document) == 0) ++ { ++ /* Parsed successfully. */ ++ discard_cleanups (result_cleanup); ++ return data.sysinfo; ++ } ++ else ++ { ++ warning (_("Could not load XML syscalls info; ignoring")); ++ do_cleanups (result_cleanup); ++ return NULL; ++ } ++} ++ ++const struct syscalls_info * ++xml_init_syscalls_info (const char *filename) ++{ ++ char *full_file; ++ char *dirname; ++ struct syscalls_info *sysinfo; ++ struct cleanup *back_to; ++ ++ full_file = fetch_xml_from_file (filename, gdb_datadir); ++ if (full_file == NULL) ++ { ++ warning (_("Could not open \"%s\""), filename); ++ return NULL; ++ } ++ ++ back_to = make_cleanup (xfree, full_file); ++ ++ dirname = ldirname (filename); ++ if (dirname != NULL) ++ make_cleanup (xfree, dirname); ++ ++ sysinfo = syscall_parse_xml (full_file, fetch_xml_from_file, dirname); ++ do_cleanups (back_to); ++ ++ return sysinfo; ++} ++ ++int ++xml_get_syscall_number (const struct syscalls_info *sysinfo, ++ const char *syscall_name) ++{ ++ struct syscall_desc *sysdesc; ++ int i; ++ ++ if (sysinfo == NULL ++ || syscall_name == NULL) ++ return UNKNOWN_SYSCALL; ++ ++ for (i = 0; ++ VEC_iterate(syscall_desc_p, sysinfo->syscalls, i, sysdesc); ++ i++) ++ if (strcmp (sysdesc->name, syscall_name) == 0) ++ return sysdesc->number; ++ ++ return UNKNOWN_SYSCALL; ++} ++ ++const char * ++xml_get_syscall_name (const struct syscalls_info *sysinfo, ++ int syscall_number) ++{ ++ struct syscall_desc *sysdesc; ++ int i; ++ ++ if (sysinfo == NULL ++ || syscall_number < 0) ++ return NULL; ++ ++ for (i = 0; ++ VEC_iterate(syscall_desc_p, sysinfo->syscalls, i, sysdesc); ++ i++) ++ if (sysdesc->number == syscall_number) ++ return sysdesc->name; ++ ++ return NULL; ++} ++ ++int ++xml_number_of_syscalls (const struct syscalls_info *sysinfo) ++{ ++ return (sysinfo == NULL ? 0 : VEC_length(syscall_desc_p, ++ sysinfo->syscalls)); ++} ++ ++const char ** ++xml_list_of_syscalls (const struct syscalls_info *sysinfo) ++{ ++ struct syscall_desc *sysdesc; ++ const char **names = NULL; ++ int nsyscalls; ++ int i; ++ ++ if (sysinfo == NULL) ++ return NULL; ++ ++ nsyscalls = VEC_length (syscall_desc_p, sysinfo->syscalls); ++ names = xmalloc ((nsyscalls + 1) * sizeof (char *)); ++ ++ for (i = 0; ++ VEC_iterate (syscall_desc_p, sysinfo->syscalls, i, sysdesc); ++ i++) ++ names[i] = sysdesc->name; ++ ++ names[i] = NULL; ++ ++ return names; ++} ++ ++#endif /* HAVE_LIBEXPAT */ +diff --git a/gdb/xml-syscall.h b/gdb/xml-syscall.h +new file mode 100644 +index 0000000..ff11f20 +--- /dev/null ++++ b/gdb/xml-syscall.h +@@ -0,0 +1,64 @@ ++/* Functions that provide the mechanism to parse a syscall XML file ++ and get its values. ++ ++ Copyright (C) 1986, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, ++ 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007, 2008 ++ Free Software Foundation, Inc. ++ ++ This file is part of GDB. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++#ifndef XML_SYSCALL_H ++#define XML_SYSCALL_H 1 ++ ++/* Structure that stores information about the system's ++ syscalls. */ ++ ++struct syscalls_info; ++ ++ ++/* Function responsible for initializing the information ++ about the syscalls. It reads the XML file and fills the ++ struct syscalls_info with the values. ++ ++ Returns the struct syscalls_info if the file is valid, NULL otherwise. */ ++ ++const struct syscalls_info *xml_init_syscalls_info (const char *); ++ ++/* Function that retrieves the syscall number corresponding to the given ++ name. ++ ++ Returns the syscall number if found, or otherwise. */ ++ ++int xml_get_syscall_number (const struct syscalls_info *, const char *); ++ ++/* Function that retrieves the syscall name corresponding to the given ++ number. ++ ++ Returns the syscall name if found, NULL otherwise. */ ++const char *xml_get_syscall_name (const struct syscalls_info *, int); ++ ++/* Function that returns the number of syscalls defined in the system. ++ ++ Returns the number of syscalls, or zero otherwise. */ ++int xml_number_of_syscalls (const struct syscalls_info *); ++ ++/* Function used to retrieve the list of syscalls in the system. This list ++ is returned as an array of strings. ++ ++ Returns the list of syscalls in the system, or NULL otherwise. */ ++const char **xml_list_of_syscalls (const struct syscalls_info *sysinfo); ++ ++#endif /* XML_SYSCALL_H */ +diff --git a/opcodes/ppc-opc.c b/opcodes/ppc-opc.c +index c872db5..5e70395 100644 +--- a/opcodes/ppc-opc.c ++++ b/opcodes/ppc-opc.c +@@ -4560,8 +4560,8 @@ const struct powerpc_opcode powerpc_opcodes[] = { + + {"lhbrx", X(31,790), X_MASK, COM, PPCNONE, {RT, RA0, RB}}, + +-{"lfqx", X(31,791), X_MASK, POWER2, PPCNONE, {FRT, RA, RB}}, + {"lfdpx", X(31,791), X_MASK, POWER6, POWER7, {FRT, RA, RB}}, ++{"lfqx", X(31,791), X_MASK, POWER2, PPCNONE, {FRT, RA, RB}}, + + {"sraw", XRC(31,792,0), X_MASK, PPCCOM, PPCNONE, {RA, RS, RB}}, + {"sra", XRC(31,792,0), X_MASK, PWRCOM, PPCNONE, {RA, RS, RB}}, +@@ -4638,8 +4638,8 @@ const struct powerpc_opcode powerpc_opcodes[] = { + + {"sthbrx", X(31,918), X_MASK, COM, PPCNONE, {RS, RA0, RB}}, + +-{"stfqx", X(31,919), X_MASK, POWER2, PPCNONE, {FRS, RA, RB}}, + {"stfdpx", X(31,919), X_MASK, POWER6, PPCNONE, {FRS, RA, RB}}, ++{"stfqx", X(31,919), X_MASK, POWER2, PPCNONE, {FRS, RA, RB}}, + + {"sraq", XRC(31,920,0), X_MASK, M601, PPCNONE, {RA, RS, RB}}, + {"sraq.", XRC(31,920,1), X_MASK, M601, PPCNONE, {RA, RS, RB}}, +@@ -4801,12 +4801,12 @@ const struct powerpc_opcode powerpc_opcodes[] = { + + {"psq_l", OP(56), OP_MASK, PPCPS, PPCNONE, {FRT,PSD,RA,PSW,PSQ}}, + ++{"lfdp", OP(57), OP_MASK, POWER6, POWER7, {FRT, D, RA0}}, ++ + {"lfqu", OP(57), OP_MASK, POWER2, PPCNONE, {FRT, D, RA0}}, + + {"psq_lu", OP(57), OP_MASK, PPCPS, PPCNONE, {FRT,PSD,RA,PSW,PSQ}}, + +-{"lfdp", OP(57), OP_MASK, POWER6, POWER7, {FRT, D, RA0}}, +- + {"ld", DSO(58,0), DS_MASK, PPC64, PPCNONE, {RT, DS, RA0}}, + {"ldu", DSO(58,1), DS_MASK, PPC64, PPCNONE, {RT, DS, RAL}}, + {"lwa", DSO(58,2), DS_MASK, PPC64, PPCNONE, {RT, DS, RA0}}, +@@ -4921,10 +4921,6 @@ const struct powerpc_opcode powerpc_opcodes[] = { + {"fcfidus", XRC(59,974,0), XRA_MASK, POWER7, PPCNONE, {FRT, FRB}}, + {"fcfidus.", XRC(59,974,1), XRA_MASK, POWER7, PPCNONE, {FRT, FRB}}, + +-{"stfq", OP(60), OP_MASK, POWER2, PPCNONE, {FRS, D, RA}}, +- +-{"psq_st", OP(60), OP_MASK, PPCPS, PPCNONE, {FRS,PSD,RA,PSW,PSQ}}, +- + {"xxsldwi", XX3(60,2), XX3SHW_MASK, PPCVSX, PPCNONE, {XT6, XA6, XB6, SHW}}, + {"xxsel", XX4(60,3), XX4_MASK, PPCVSX, PPCNONE, {XT6, XA6, XB6, XC6}}, + {"xxspltd", XX3(60,10), XX3DM_MASK, PPCVSX, PPCNONE, {XT6, XA6, XB6S, DMEX}}, +@@ -5067,12 +5063,16 @@ const struct powerpc_opcode powerpc_opcodes[] = { + {"xvcvsxddp", XX2(60,504), XX2_MASK, PPCVSX, PPCNONE, {XT6, XB6}}, + {"xvnegdp", XX2(60,505), XX2_MASK, PPCVSX, PPCNONE, {XT6, XB6}}, + +-{"psq_stu", OP(61), OP_MASK, PPCPS, PPCNONE, {FRS,PSD,RA,PSW,PSQ}}, ++{"stfq", OP(60), OP_MASK, POWER2, PPCNONE, {FRS, D, RA}}, + +-{"stfqu", OP(61), OP_MASK, POWER2, PPCNONE, {FRS, D, RA}}, ++{"psq_st", OP(60), OP_MASK, PPCPS, PPCNONE, {FRS,PSD,RA,PSW,PSQ}}, + + {"stfdp", OP(61), OP_MASK, POWER6, PPCNONE, {FRT, D, RA0}}, + ++{"stfqu", OP(61), OP_MASK, POWER2, PPCNONE, {FRS, D, RA}}, ++ ++{"psq_stu", OP(61), OP_MASK, PPCPS, PPCNONE, {FRS,PSD,RA,PSW,PSQ}}, ++ + {"std", DSO(62,0), DS_MASK, PPC64, PPCNONE, {RS, DS, RA0}}, + {"stdu", DSO(62,1), DS_MASK, PPC64, PPCNONE, {RS, DS, RAS}}, + {"stq", DSO(62,2), DS_MASK, POWER4, PPCNONE, {RSQ, DS, RA0}}, -- 2.44.0